一、建造者模式简介
1.1、定义
建造者模式指将一个复杂的对象构造过程和对象的表示进行分离。使同样的建造过程可以创建不同的表示,将构建过程拆分成多个简单的对象,将不变和变进行分离。不变的是对象的组成部分,变化的是每个部分的具体内容。
比如建造汽车的过程,不变的是都需要车身、底盘、车轮、发动机等组件,变化的是每个组件可以有不同的构造过程。
1.2、优缺点
a.封装性好,构建和表示进行分离
b.扩展性好,各个具体的建造者相互独立,各个组件之间互相解耦
c.对象调用者无需关系对象的具体建造过程,满足迪米特法则
1.3、建造者模式的角色
产品:需要建造的对象,通常包含是由多个简单的组件组合成的复杂对象
抽象建造者:包含创建产品各个子部件的抽象方法的接口,通过还包含一个返回复杂对象的方法用于返回建造后的对象
具体建造者:实现抽象建造者,完成复杂产品各个子部件的具体创建
指挥者:调用建造者对象中的部件构造方法与装配方法完成复杂对象的创建,指挥者不关心具体产品的信息
二、建造者模式案例
1、业务场景
构造一个汽车对象,汽车对象包含了车身、底盘、发动机、车轮等核心组件
2、代码实现
a.定义汽车对象及各个组件的实体类
1 /** 2 * 汽车类 3 */ 4 public class Car { 5 6 //车架 7 private CarFrame frame; 8 9 //发动机 10 private Engine engine; 11 12 //底盘 13 private Chassis chassis; 14 15 //车轮 16 private Wheel wheel; 17 18 public CarFrame getFrame() { 19 return frame; 20 } 21 22 public void setFrame(CarFrame frame) { 23 this.frame = frame; 24 } 25 26 public Engine getEngine() { 27 return engine; 28 } 29 30 public void setEngine(Engine engine) { 31 this.engine = engine; 32 } 33 34 public Chassis getChassis() { 35 return chassis; 36 } 37 38 public void setChassis(Chassis chassis) { 39 this.chassis = chassis; 40 } 41 42 public Wheel getWheel() { 43 return wheel; 44 } 45 46 public void setWheel(Wheel wheel) { 47 this.wheel = wheel; 48 } 49 }
b.定义抽象建造者,提供返回对象的方法并定义汽车对象构建各个子部件的抽象
1 /** 2 * 抽象汽车建造者 3 */ 4 public abstract class CarBuilder { 5 6 protected Car car = new Car(); 7 8 /** 返回构造的汽车对象*/ 9 public Car builder(){ 10 return car; 11 } 12 13 /** 构建车架*/ 14 public abstract CarBuilder frame(); 15 16 /** 构建发动机*/ 17 public abstract CarBuilder engine(); 18 19 /** 构建底盘*/ 20 public abstract CarBuilder chassis(); 21 22 /** 构建车轮*/ 23 public abstract CarBuilder wheel(); 24 }
c.实现具体的建造者,如奔驰汽车建造者
1 /** 2 * 奔驰汽车建造者实现类 3 */ 4 public class BenzCarBuilder extends CarBuilder{ 5 6 @Override 7 public CarBuilder frame() { 8 System.out.println("奔驰建造者构建车轮"); 9 car.setFrame(new CarFrame("奔驰车轮")); 10 return this; 11 } 12 13 @Override 14 public CarBuilder engine() { 15 System.out.println("奔驰建造者构建发动机"); 16 car.setEngine(new Engine("奔驰发动机")); 17 return this; 18 } 19 20 @Override 21 public CarBuilder chassis() { 22 System.out.println("奔驰建造者构建底盘"); 23 car.setChassis(new Chassis("奔驰底盘")); 24 return this; this; 25 } 26 27 @Override 28 public CarBuilder wheel() { 29 System.out.println("奔驰建造者构建车轮"); 30 car.setWheel(new Wheel("奔驰车轮")); 31 return this; 32 } 33 }
测试代码如下:
1 public static void main(String[] args){ 2 CarBuilder builder = new BenzCarBuilder(); 3 /** 通过奔驰建造者构建汽车对象 */ 4 Car car = builder.frame().engine().chassis().builder(); 5 System.out.println(JSON.toJSONString(car)); 6 }
1 奔驰建造者构建车轮 2 奔驰建造者构建发动机 3 奔驰建造者构建底盘 4 {"chassis":{"name":"奔驰底盘"},"engine":{"name":"奔驰发动机"},"frame":{"name":"奔驰车轮"}}
调用方main函数中无需关心汽车是如何构建的,只需要关心需要将哪些组件组合到汽车对象上。如果汽车需要增加或者删除一些组件,只需要在抽象建造者中增加或删除对应的方法即可,比如需要添加仪表盘组件,则只需要定义仪表盘对象,并且在抽象建造者中添加对应的方法即可,代码如下:
定义仪表盘类DashBoard类,并在Car中添加属性,修改抽象建造者类,添加构造仪表盘的方法
1 /** 2 * 抽象汽车建造者 3 */ 4 public abstract class CarBuilder { 5 6 protected Car car = new Car(); 7 8 /** 返回构造的汽车对象*/ 9 public Car builder(){ 10 return car; 11 } 12 13 /** 构建车架*/ 14 public abstract CarBuilder frame(); 15 16 /** 构建发动机*/ 17 public abstract CarBuilder engine(); 18 19 /** 构建底盘*/ 20 public abstract CarBuilder chassis(); 21 22 /** 构建车轮*/ 23 public abstract CarBuilder wheel(); 24 25 /** 构建仪表盘*/ 26 public abstract CarBuilder bashBoard(); 27 }
此时构造汽车时就可以加上仪表盘的构造
1 public static void main(String[] args){ 2 CarBuilder builder = new BenzCarBuilder(); 3 /** 通过奔驰建造者构建汽车对象 */ 4 Car car = builder.frame().engine().chassis().bashBoard().builder(); 5 System.out.println(JSON.toJSONString(car)); 6 }
另外本例子中的具体建造者是直接实现了构建细节,还可以改造成将构建细节分离,将构建的组件进行抽象化,比如将上例中的需求改动,汽车不再由奔驰建造者来建造,而是由一个第三方建造者来构建,第三方建造者造汽车时可能会用保时捷的发动机、奔驰的车身、宝马的底盘和奥迪的仪表盘,此时将构建细节交给具体建造者的化就不好扩展,所以具体建造者应该将构建组件的部分抽象分离出去。代码如下:
将各个组件抽象化
/** * 车架组件 */ public interface CarFrame { public String name(); } /** * 底盘组件 */ public interface Chassis { public String name(); } /** * 发动机组件 */ public interface Engine { public String name(); } /** * 车轮组件 */ public interface Wheel { public String name(); } /** * 仪表盘抽象 */ public interface BashBoard { public String name(); }
修改抽象建造者类,此时由于组件是直接由外部构建,那么可以直接去除建造者类的抽象定义,直接由建造者类构建即可,代码如下:
1 /** 2 * 抽象汽车建造者 3 */ 4 public class CarBuilder { 5 6 protected Car car = new Car(); 7 8 /** 返回构造的汽车对象*/ 9 public Car builder(){ 10 return car; 11 } 12 13 /** 构建车架*/ 14 public CarBuilder frame(CarFrame carFrame){ 15 car.setFrame(carFrame); 16 return this; 17 } 18 19 /** 构建发动机*/ 20 public CarBuilder engine(Engine engine){ 21 car.setEngine(engine); 22 return this; 23 } 24 25 /** 构建底盘*/ 26 public CarBuilder chassis(Chassis chassis){ 27 car.setChassis(chassis); 28 return this; 29 } 30 31 /** 构建车轮*/ 32 public CarBuilder wheel(Wheel wheel){ 33 car.setWheel(wheel); 34 return this; 35 } 36 37 /** 构建仪表盘*/ 38 public CarBuilder bashBoard(BashBoard bashBorad){ 39 car.setBashBoard(bashBorad); 40 return this; 41 } 42 }
测试代码如下:
1 public static void main(String[] args){ 2 CarBuilder builder = new CarBuilder(); 3 /** 通过建造者类构建汽车对象 */ 4 Car car = builder 5 .frame(new BenzFrame())//奔驰车架 6 .engine(new PorscheEngine())//保时捷发动机 7 .chassis(new BmwChassis())//宝马底盘 8 .bashBoard(new AudiBashBoard())//奥迪仪表盘 9 .wheel(new MichelinWheel())//米其林车轮 10 .builder(); 11 System.out.println(car.toString()); 12 }
1 {"engine":"保时捷发动机","wheel":"米其林车轮","chassis":"宝马底盘","bashBoard":"奥迪仪表盘","frame":"奔驰车架"}
两种实现方式都各自有各自的优点,可以根据具体的业务场景选择更方便的更具有扩展性的方式来实现。
三、建造者模式和工厂模式的对比
1、建造者不关注组件的生产过程,只关心复杂对象的构建过程;而工厂模式需要关心各个组件的生产过程;
2、建造者倾向于建造结构相同内容不同的对象;工厂模式倾向于批量生产结构相同且内容也相同的对象;
3、建造者模式中客户端可以控制如何构造对象的组件;工厂模式中客户端无法控制构建对象的细节;
可以表示中建造者模式更加注重的是创建对象的过程;工厂模式更加注重的是创建对象的结果。