学习建造者模式前,我们来实现一个汉堡的制作流程

 

汉堡制作的大致流程:
首先是加入两个面包片
加入肉饼
加入蔬菜
加热
打包

代码:

 1 public class Builder1 {
 2     public static void main(String[] args) {
 3         Hamburger hamburger1 = new Hamburger("巨无霸", "吐司", "莴笋", "牛肉饼");
 4         hamburger1.setBread();
 5         hamburger1.setMeatPie();
 6         hamburger1.setVegetableLeaf();
 7         hamburger1.heating(10);
 8         hamburger1.pack();
 9     }
10 }
11 
12 class Hamburger {
13     private String name;//汉堡包名字
14     private String bread;//面包片
15     private String vegetableLeaf;//菜叶名
16     private String meatPie;//肉饼名
17 
18     Hamburger(String name, String bread, String vegetableLeaf, String meatPie) {
19         this.name = name;
20         this.bread = bread;
21         this.vegetableLeaf = vegetableLeaf;
22         this.meatPie = meatPie;
23     }
24 
25     void setBread() {
26         System.out.println("加入面包片:" + this.bread);
27     }
28 
29     void setVegetableLeaf() {
30         System.out.println("向汉堡加入" + this.vegetableLeaf);
31     }
32 
33     void setMeatPie() {
34         System.out.println("向汉堡加入" + this.meatPie);
35     }
36 
37 
38     void heating(int minute) {
39         System.out.println("汉堡加热时间" + minute + "分钟");
40     }
41 
42     void pack() {
43         System.out.println(this.name + "汉堡加工完成,打包!");
44     }
45 }

运行的结果:

 

功能实现啦,看起来也像一个“面向对象”的程序,把汉堡抽象出来了,同时汉堡中封装他独有的方法和属性。
但是仔细看看客户端代码,我们在客户端新建了一个汉堡,然后对他进行了一系列的操作,最后完成了汉堡。

 

建造者模式就是将一些列操作封装起来的一种模式


但是出现了最大的问题:代码不可复用,每一次客户端需要汉堡的时候都需要加工一次
不可复用的结果就可能导致每一次加工出来的汉堡都不一样,不是流水化作业
比如工序的顺序颠倒了,比如多一个工序或者少一个工序,导致加工出来的汉堡都不是我们想要的汉堡,不是我们想要的对象。

 

让我们来看看建造者模式时怎么实现这段代码

 1 public class Builder2 {
 2     public static void main(String[] args) {
 3         Hamburger1 hamburger1 = new KFCHamburger("鸡肉汉堡", "面包", "韭菜", "鸡肉饼");
 4         HamburgerBuilder hamburgerBuilder = new HamburgerBuilder(hamburger1);
 5         hamburgerBuilder.buildHamburger();
 6     }
 7 }
 8 
 9 abstract class Hamburger1 {
10     String name;
11     String bread;//面包片
12     String vegetableLeaf;//菜叶名
13     String meatPie;//肉饼名
14     private int heatingTime;//加热时间
15 
16     Hamburger1(String name, String bread, String vegetableLeaf, String meatPie) {
17         this.name = name;
18         this.bread = bread;
19         this.vegetableLeaf = vegetableLeaf;
20         this.meatPie = meatPie;
21         this.heatingTime = 0;
22     }
23 
24     abstract void setBread();
25 
26     abstract void setVegetableLeaf();
27 
28     abstract void setMeatPie();
29 
30     abstract void heating(int minute);
31 
32     abstract void pack();
33 }
34 
35 class KFCHamburger extends Hamburger1 {
36     public KFCHamburger(String name, String bread, String vegetableLeaf, String meatPie) {
37         super(name, bread, vegetableLeaf, meatPie);
38     }
39 
40     @Override
41     void setBread() {
42         System.out.println("加入面包片:" + this.bread);
43     }
44 
45     @Override
46     void setVegetableLeaf() {
47         System.out.println("向汉堡加入" + this.vegetableLeaf);
48     }
49 
50     @Override
51     void setMeatPie() {
52         System.out.println("向汉堡加入" + this.meatPie);
53     }
54 
55     @Override
56     void heating(int minute) {
57         System.out.println("汉堡加热时间" + minute + "分钟");
58     }
59 
60     @Override
61     void pack() {
62         System.out.println(this.name + "汉堡加工完成,打包!");
63     }
64 }
65 
66 class HamburgerBuilder {
67     private Hamburger1 hamburger1;
68 
69     HamburgerBuilder(Hamburger1 hamburger1) {
70         this.hamburger1 = hamburger1;
71     }
72 
73     Hamburger1 buildHamburger() {
74         hamburger1.setBread();
75         hamburger1.setMeatPie();
76         hamburger1.setVegetableLeaf();
77         hamburger1.heating(10);
78         hamburger1.pack();
79         return this.hamburger1;
80     }
81 }


看完这段代码是不是觉得建造者模式也很厉害

UML图

 

建造者模式UML

 

product:我们需要的产品对象

Builder:对产品对象的加工方法

Director:封装生产对象的过程,返回一个加工好的对象。

(类似于工厂模式,将对象的生产过程封装起来,只返回一个立即可用的对象)

 

更正一下:应该把生成对象的方法抽象到建造类中,而不是放在对象之中,所以看起会和建造者UML的图看起来有点点不一样

我写的HamburgerBuilder其实对应的Director导演的位置,而建造者的方法我全部封装在Product中了。

有时间会修改我的代码的

 

分析下:
解决了代码不能复用的问题了 (可复用)
同时如果我们现在要把汉堡的的加热时间修改下,或者把肉片和蔬菜放置的顺序换一下。只需要到建造类中修改时间即可。
如果我们将代码写在客户端,那么维护起来就是种灾难!(可维护)
如果我们现在要加入一个巨无霸汉堡,他有三层肉片,2层蔬菜,加热20分钟怎么办呢
我们只需要到建造类中加入生产巨无霸汉堡的代码即可(可谓可扩展,灵活性高)

 1 public static void main(String[] args) {
 2     Hamburger1 hamburger1 = new KFCHamburger("巨无霸", "面包", "韭菜", "鸡肉饼");
 3     HamburgerBuilder hamburgerBuilder = new HamburgerBuilder(hamburger1);
 4     hamburgerBuilder.buildBigBigBigHamburger();//修改建造的方法即可
 5 }
 6 
 7 Hamburger1 buildBigBigBigHamburger() {
 8     hamburger1.setBread();
 9     hamburger1.setMeatPie();//肉片1
10     hamburger1.setVegetableLeaf();//蔬菜1
11     hamburger1.setMeatPie();//肉片2
12     hamburger1.setVegetableLeaf();//蔬菜2
13     hamburger1.setMeatPie();//肉片3
14     hamburger1.heating(20);
15     hamburger1.pack();
16     return this.hamburger1;
17 }

我们来看看结果吧

建造者面膜是和工厂模式同属于创建型模式(创建型模式:负责对象的创建


什么场景下使用建造者模式

1.产品对象内部具有复杂的结构,产品对象包含多个成员属性,适用建造者模式可以隔离复杂对象的创建和适用,并使得相同的 创建过程可以创建不同的对象;
2.相同的方法,不同的执行顺序,产生不同的事件结果时;(汉堡的加工顺序)


简单来说,建造者模式就是一步步创建一个对象,它对用户屏蔽了里面构建的细节(顺序,调用次数...),但却可以精细地控制对象的构造过程。

 

代码地址:https://gitee.com/gang_bryant/DesignMode1