学习建造者模式前,我们来实现一个汉堡的制作流程
汉堡制作的大致流程:
首先是加入两个面包片
加入肉饼
加入蔬菜
加热
打包
代码:
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