建造者模式:深入理解建造者模式 ——组装复杂的实例

目录:

一 建造者模式介绍

1.1 定义

1.2 为什么要用建造者模式(优点)?

1.3 哪些情况不要用建造者模式(缺点)?

1.4 抽象工厂模式VS建造者模式

1.4 模式结构

  • 1.4.1 建造者模式的UML结构图
  • 1.4.2 建造者模式主要包含四个角色

二 建造者模式分析

三 实例:KFC套餐

  • 1)Product(产品角色)
  • 2)Builder(抽象建造者)
  • 3)ConcreteBuilder(具体建造者)
  • 4)Director(指挥者)
  • 5)测试类(客户端类)

四 总结

无论是在现实世界中还是在软件系统中,都存在一些复杂的对象,它们拥有多个组成部分,如汽车,它包括车轮、方向盘、发送机等各种部件。而对于大多数用户而言,无须知道这些部件的装配细节,也几乎不会使用单独某个部件,而是使用一辆完整的汽车,可以通过建造者模式对其进行设计与描述,建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节.

50439782.jpg

一 建造者模式介绍

1.1 定义

建造者模式(Builder Pattern) 又名生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。

建造者模式 是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。

68223661.jpg

1.2 为什么要用建造者模式(优点)?

  1. 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。

  2. 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象 。

  3. 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

  4. 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合 “开闭原则”

1.3 哪些情况不要用建造者模式(缺点)?

  1. 产品之间差异性很大的情况:建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

  2. 产品内部变化很复杂的情况: 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

1.4 抽象工厂模式VS建造者模式
抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。

1.4 模式结构

1.4.1 建造者模式的UML结构图


24724195.jpg

1.4.2 建造者模式主要包含四个角色
Product(产品角色):一个具体的产品对象。
Builder(抽象建造者):创建一个Product对象的各个部件指定的抽象接口。
ConcreteBuilder(具体建造者):实现抽象接口,构建和装配各个部件。
Director(指挥者):构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。

二 建造者模式分析
1 ) 一个典型的复杂对象其类代码示例如下:

public class Product 
{
private String partA; //可以是任意类型
private String partB;
private String partC;
//partA的Getter方法和Setter方法省略
//partB的Getter方法和Setter方法省略
//partC的Getter方法和Setter方法省略
}

2 ) 抽象建造者类中定义了产品的创建方法和返回方法,其典型代码如下:

public abstract class Builder
{
protected Product product=new Product();

public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();

public Product getResult()
{
return product;
}
} 

3 ) 具体建造者。实现抽象接口,构建和装配各个部件,实例代码如下:

public class ConcreteBuilder extends Builder{
public void buildPartA(){
...
}
public void buildPartB(){
...
}
public void buildPartC(){
...
}
}

4)指挥者类的代码示例如下:

建造者模式的结构中还引入了一个指挥者类Director,该类的作用主要有两个:一方面它隔离了客户与生产过程;另一方面它负责控制产品的生成过程。指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象。

public class Director
{
private Builder builder;
//1 构造方法的方式注入builder对象
public Director(Builder builder)
{
this.builder=builder;
}
//2 set方法注入builder对象
public void setBuilder(Builder builder)
{
this.builder=builer;
}

public Product construct()
{
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
} 

5 ) 客户端类代码片段:

在客户端代码中,无须关心产品对象的具体组装过程,只需确定具体建造者的类型即可,建造者模式将复杂对象的构建与对象的表现分离开来,这样使得同样的构建过程可以创建出不同的表现。

……
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
Product product = director.construct();
……

三 实例:KFC套餐

建造者模式可以用于描述KFC如何创建套餐:套餐是一个复杂对象,它一般包含主食(如汉堡、鸡肉卷等)和饮料(如果汁、可乐等)等组成部分,不同的套餐有不同的组成部分,而KFC的服务员可以根据顾客的要求,一步一步装配这些组成部分,构造一份完整的套餐,然后返回给顾客。

58066865.jpg

1)Product(产品角色)
一个具体的产品对象。

public class Meal {
private String food;
private String drink;

public String getFood() {
return food;
}

public void setFood(String food) {
this.food = food;
}

public String getDrink() {
return drink;
}

public void setDrink(String drink) {
this.drink = drink;
}
}

2)Builder(抽象建造者)
创建一个Product对象的各个部件指定的抽象接口。

public abstract class MealBuilder {
Meal meal = new Meal();

public abstract void buildFood();

public abstract void buildDrink();

public Meal getMeal(){
return meal;
}
}

3) ConcreteBuilder(具体建造者)
实现抽象接口,构建和装配各个部件。

A套餐:

public class MealA extends MealBuilder{

public void buildDrink() {
meal.setDrink("可乐");
}

public void buildFood() {
meal.setFood("薯条");
}

}

B套餐:

public class MealB extends MealBuilder{

public void buildDrink() {
meal.setDrink("柠檬果汁");
}

public void buildFood() {
meal.setFood("鸡翅");
}

}

4)Director(指挥者)
构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象,它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。

public class KFCWaiter {
private MealBuilder mealBuilder;

public KFCWaiter(MealBuilder mealBuilder) {
this.mealBuilder = mealBuilder;
}


public Meal construct(){
//准备食物
mealBuilder.buildFood();
//准备饮料
mealBuilder.buildDrink();

//准备完毕,返回一个完整的套餐给客户
return mealBuilder.getMeal();
}
}

5)测试类(客户端类)
public class Test {
public static void main(String[] args) {

//套餐A
MealA a = new MealA();
//准备套餐A的服务员
KFCWaiter waiter = new KFCWaiter(a);
//获得套餐
Meal mealA = waiter.construct();  
System.out.print("套餐A的组成部分:");
System.out.println("食物:"+mealA.getFood()+";   "+"饮品:"+mealA.getDrink());
}
}

输出结果:

套餐A的组成部分:食物:薯条; 饮品:可乐
1
2

四 总结

本文首先介绍了建造者模型包括建造者模型的定义、为什么要用它、那些情况不适合使用这种模式以及抽象工厂模式和建造者模式的区别的简单分析。

然后通过建造者模式的四个角色的常见示例代码,通过代码层面分析了建造者模式。

最后通过一个KFC套餐实例,介绍了建造者模式在实例中的基本使用手段。

参考:

《设计模式之禅》

《图解设计模式》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 没有人买车会只买一个轮胎或者方向盘,大家买的都是一辆包含轮胎、方向盘和发动机等多个部件的完整汽车。如何将这些部件组...
    justCode_阅读 1,821评论 1 6
  • 【学习难度:★★★★☆,使用频率:★★☆☆☆】直接出处:建造者模式梳理和学习:https://github.com...
    BruceOuyang阅读 762评论 0 5
  • 模式动机 无论是在现实世界中还是在软件系统中,都存在一些复杂的对象,它们拥有多个组成部分,如汽车,它包括车轮、方向...
    lijun_m阅读 412评论 0 0
  • 1《环太平洋》美 很多年前在电影院看过这个电影,最近又翻出这个电影,只是在累的时候,看看这样打怪兽的片子是一个很好...
    风筝2017阅读 302评论 0 0
  • 1 松一是一只被困在南方的北方松鼠。 在999年之前的一个风雨交加的晚上,他匆忙藏好了准备越冬的食物之后,便屁颠屁...
    关机小姐阅读 377评论 2 3