文档章节

浅谈设计模式之建造者模式

佛系程序猿灬
 佛系程序猿灬
发布于 07/03 20:10
字数 1460
阅读 1741
收藏 33
点赞 4
评论 4

介绍

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

何时使用:一些基本部件不会变,而其组合经常变化的时候。

如何解决:将变与不变分离开。

关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。3、SQL中的PreparedStatement

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。

注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

实现

我们假设一个快餐店的商业案例,去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。其中,一个典型的套餐可以是一个汉堡(Burger)和一杯冷饮(Cold drink)。汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒中。冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中。

我们将创建一个表示食物条目(比如汉堡和冷饮)的 Item 接口和实现 Item 接口的实体类,以及一个表示食物包装的 Packing 接口和实现 Packing 接口的实体类,汉堡是包在纸盒中,冷饮是装在瓶子中。

然后我们创建一个 Meal 类,带有 Item 的 ArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilderBuilderPatternDemo,我们的演示类使用 MealBuilder 来创建一个 Meal

代码示例:

1、创建一个表示食物条目和食物包装的接口 ItemPacking

package builder.item.service;

import builder.pack.service.Packing;

/**
 * 食物条目接口
 * @author lihaoshan
 * @date 2018-06-27
 * */
public interface Item {

    /**名字*/
    public String name();

    /**价格*/
    public Double price();


    public Packing packing();
}
package builder.pack.service;

/**
 * 包装接口
 * @author lihaoshan
 * @date 2018-06-27
 * */
public interface Packing {

    /**包装*/
    public String pack();
}

2、创建 Packing 接口的实现类

package builder.pack.impl;

import builder.pack.service.Packing;

/**
 * 包装接口实现类【瓶装】
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class Bottle implements Packing{

    @Override
    public String pack(){
        return "瓶装";
    }
}
package builder.pack.impl;

import builder.pack.service.Packing;

/**
 * 包装接口实现类【纸盒包装】
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class Wrapper implements Packing {

    @Override
    public String pack(){
        return "纸盒包装";
    }
}

3、创建实现 Item 接口的抽象类

package builder.item.impl;

import builder.pack.impl.Wrapper;
import builder.item.service.Item;
import builder.pack.service.Packing;

/**
 * 食物条目实现抽象类【汉堡】
 * @author lihaoshan
 * @date 2018-06-28
 * */
public abstract class Burger implements Item{

    @Override
    public Packing packing(){
        return new Wrapper();
    }

    @Override
    public abstract Double price();

}
package builder.item.impl;

import builder.pack.impl.Bottle;
import builder.item.service.Item;
import builder.pack.service.Packing;

/**
 * 食物条目实现抽象类【可乐】
 * @author lihaoshan
 * @date 2018-06-28
 * */
public abstract class ColdDrink implements Item{

    @Override
    public Packing packing(){
        return new Bottle();
    }

    @Override
    public abstract Double price();
}

4、创建扩展了 BurgerColdDrink 的实体类

package builder.po;

import builder.item.impl.Burger;

/**
 * 扩展Burger的实体类【鸡肉汉堡】
 *
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class ChickenBurger extends Burger{

    @Override
    public Double price(){
        return 30.0;
    }

    @Override
    public String name(){
        return "鸡肉汉堡";
    }
}
package builder.po;

import builder.item.impl.ColdDrink;

/**
 * 扩展ColdDrink的实体类【可口可乐】
 *
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class Coke extends ColdDrink{

    @Override
    public Double price(){
        return 10.0;
    }

    @Override
    public String name(){
        return "可口可乐";
    }
}
package builder.po;

import builder.item.impl.ColdDrink;

/**
 * 扩展ColdDrink的实体类【百事可乐】
 *
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class Pepsi extends ColdDrink{

    @Override
    public Double price(){
        return 12.0;
    }

    @Override
    public String name(){
        return "百事可乐";
    }
}
package builder.po;

import builder.item.impl.Burger;

/**
 * 扩展Burger的实体类【素食汉堡】
 *
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class VegBurger extends Burger {

    @Override
    public Double price() {
        return 25.0;
    }

    @Override
    public String name() {
        return "素食汉堡";
    }
}

5、创建点餐类 Meal,带有食物条目对象 

package builder;

import builder.item.service.Item;

import java.util.ArrayList;
import java.util.List;

/**
 * 点餐类,带有食物条目对象
 *
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class Meal {

    /**食物条目对象*/
    private List<Item> items = new ArrayList<Item>();

    /**
     * 点餐方法
     *
     * @param item
     * */
    public void addItem(Item item){
        items.add(item);
    }

    /**
     * 点餐费用
     *
     * */
    public Double getCost(){

        Double cost = 0.0;
        for (Item item : items) {
            cost +=item.price();
        }
        return cost;
    }

    /**
     * 展示食物条目
     *
     * */
    public void showItems(){
        System.out.println("菜单\t\t\t\t包装\t\t\t\t费用\n");
        for (Item item : items) {
            System.out.print(item.name()+"\t\t\t"+item.packing().pack()+"\t\t\t"+item.price()+"\n");
        }
    }
}

6、创建一个点餐服务类 MealBuilder 

package builder;

import builder.po.ChickenBurger;
import builder.po.Coke;
import builder.po.Pepsi;
import builder.po.VegBurger;

/**
 * 点餐服务类
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class MealBuilder {

    /**
     * 素食套餐
     * */
    public Meal prepareVegMeal(){
        Meal meal = new Meal();
        meal.addItem(new VegBurger());
        meal.addItem(new Coke());
        return meal;
    }

    /**
     * 非素食套餐
     * */
    public Meal prepareNonVegMeal(){
        Meal meal = new Meal();
        meal.addItem(new ChickenBurger());
        meal.addItem(new Pepsi());
        return meal;
    }

}

7、创建一个测试类 BuiderPatternDemo

package builder;

import org.junit.Test;

/**
 * 建造者模式 测试类
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class BuilderPatternDemo {

    @Test
    public void test(){
        MealBuilder mealBuilder = new MealBuilder();

        Meal vegMeal = mealBuilder.prepareVegMeal();
        System.out.println("***************素食餐***************");
        vegMeal.showItems();
        System.out.println("总合计: " +vegMeal.getCost());

        Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
        System.out.println("\n\n***************非素食餐***************");
        nonVegMeal.showItems();
        System.out.println("总合计: " +nonVegMeal.getCost());
    }
}

8、运行结果如下:

源码地址

码云:https://gitee.com/haoshan/design_pattern

 

欢迎各位大佬关注我的个人微信订阅号:

© 著作权归作者所有

共有 人打赏支持
佛系程序猿灬
粉丝 10
博文 6
码字总数 7997
作品 0
南京
程序员
加载中

评论(4)

A
AntennaBaby

引用来自“jiabei”的评论

为什么百事可乐比可口可乐贵两块钱
666老哥真的严格.
♂茶舞
♂茶舞
这与组合模式有什么区别?
佛系程序猿灬
佛系程序猿灬

引用来自“jiabei”的评论

为什么百事可乐比可口可乐贵两块钱
看来大佬是用心了,看问题很是犀利啊
jiabei
jiabei
为什么百事可乐比可口可乐贵两块钱
JavaScript设计模式系列二之建造者模式(附案例源码)

文章初衷 设计模式其实旨在解决语言本身存在的缺陷, 目前javaScript一些新的语法特性已经集成了一些设计模式的实现, 大家在写代码的时候,没必要为了用设计模式而去用设计模式, 那么我这边为什...

小钱钱阿圣
2017/09/11
0
0
设计模式(Swift) - 3.观察者模式、建造者模式

上一篇 设计模式(Swift) - 2.单例模式、备忘录模式和策略模式中讲了三种常见的设计模式. 单例模式: 限制了类的实例化,一个类只能实例化一个对象,所有对单例对象的引用都是指向了同一个对象....

Dariel
07/01
0
0
设计模式8——Builder设计模式

Builder建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。Builder模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就...

小米米儿小
2013/12/11
0
0
java设计模式-- 单例模式

在很久之前,也就是在大二暑假的时候,那时候看马士兵的视频教程中有提到很多的设计模式。 java的设计模式大致可以分为3大类,23种设计模式。 其中,创建型模式有5种:单例模式、建造者模式、...

爱学习的逃课君
2014/11/27
0
0
(目录)设计模式(可复用面向对象软件的基础)

本系列“设计模式”博客使用Golang语言实现算法。所谓算法是指解决一个问题的步骤,个人觉得不在于语言。小弟只是最近学习Golang,所以顺带熟练一下语法知识,别无它意。 本系列博客主要介绍...

chapin
2015/01/13
0
0
设计模式Java Design Pattern-工厂方法模式FactoryMethod

我的博客 一、 设计模式的分类 大体可以分为三类: 创建型模式(5个) 单例模式、原型模式、工厂方法模式、抽象工厂模式、建造者模式 结构性模式(7个) 适配器模式、装饰器模式、代理模式、...

勇敢写信
03/22
0
0
小菜学设计模式——设计模式总结之创建型

1、面向过程与面向对象 1)面向过程通过划分功能模块,通过函数间相互调用来实现,但需求变化时就需要更改函数,而你改动的函数有多少地方在调用她呢?关联多少数据,这是很不容易弄得清楚地...

learn_more
2015/07/05
0
0
23种设计模式(4):建造者模式

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 类型:创建类模式 类图: 四个要素 产品类:一般是一个较为复杂的对象,也就是说创建对象的过程比较复杂...

LCZ777
2014/07/05
0
0
设计模式 2014-12-19

book: 阎宏《JAVA与模式》 架构设计栏目 http://blog.csdn.net/enterprise/column.html 概要: http://bbs.csdn.net/forums/Embeddeddriver 23种设计模式分别是: 1.单例模式 2.工厂方法模式...

jayronwang
2014/12/19
0
0
代理模式(Proxy Pattern):动态代理 - 最易懂的设计模式解析

前言 今天我来全面总结开发中最常用的设计模式 - 代理模式中的动态代理模式 其他设计模式介绍 1分钟全面了解“设计模式” 单例模式(Singleton) - 最易懂的设计模式解析 简单工厂模式(Sim...

Carson_Ho
04/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

shell中的函数、shell中的数组、告警系统需求分析

shell中的函数 格式: 格式: function f_name() { command } 函数必须要放在最前面 示例1(用来打印参数) 示例2(用于定义加法) 示例3(用于显示IP) shell中的数组 shell中的数组1 定义数...

Zhouliang6
今天
2
0
用 Scikit-Learn 和 Pandas 学习线性回归

      对于想深入了解线性回归的童鞋,这里给出一个完整的例子,详细学完这个例子,对用scikit-learn来运行线性回归,评估模型不会有什么问题了。 1. 获取数据,定义问题     没有...

wangxuwei
今天
1
0
MAC安装MAVEN

一:下载maven压缩包(Zip或tar可选),解压压缩包 二:打开终端输入:vim ~/.bash_profile(如果找不到该文件新建一个:touch ./bash_profile) 三:输入i 四:输入maven环境变量配置 MAVEN_HO...

WALK_MAN
今天
0
0
33.iptables备份与恢复 firewalld的9个zone以及操作 service的操作

10.19 iptables规则备份和恢复 10.20 firewalld的9个zone 10.21 firewalld关于zone的操作 10.22 firewalld关于service的操作 10.19 iptables规则备份和恢复: ~1. 保存和备份iptables规则 ~2...

王鑫linux
今天
2
0
大数据教程(2.11):keeperalived+nginx高可用集群搭建教程

上一章节博主为大家介绍了目前大型互联网项目的系统架构体系,相信大家应该注意到其中很重要的一块知识nginx技术,在本节博主将为大家分享nginx的相关技术以及配置过程。 一、nginx相关概念 ...

em_aaron
今天
1
0
Apache Directory Studio连接Weblogic内置LDAP

OBIEE默认使用Weblogic内置LDAP管理用户及组。 要整理已存在的用户及组,此前办法是导出安全数据,文本编辑器打开认证文件,使用正则表达式获取用户及组的信息。 后来想到直接用Apache Dire...

wffger
今天
2
0
HFS

FS,它是一种上传文件的软件。 专为个人用户所设计的 HTTP 档案系统 - Http File Server,如果您觉得架设 FTP Server 太麻烦,那么这个软件可以提供您更方便的档案传输系统,下载后无须安装,...

garkey
今天
1
0
Java IO类库之BufferedInputStream

一、BufferedInputStream介绍 /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to * sup......

老韭菜
今天
0
0
STM 32 窗口看门狗

http://bbs.elecfans.com/jishu_805708_1_1.html https://blog.csdn.net/a1985831055/article/details/77404131...

whoisliang
昨天
1
0
Dubbo解析(六)-服务调用

当dubbo消费方和提供方都发布和引用完成后,第四步就是消费方调用提供方。 还是以dubbo的DemoService举例 -- 提供方<dubbo:application name="demo-provider"/><dubbo:registry address="z...

青离
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部