6.建造者模式
(1).概述
将一个复杂对象的构建
与便是分离
,使得同样的构建过程可以创建不同的表示。
将主机拆开就是分离,将分离的主机合起来就是构建。在一样的构建方法中我们更换掉不同品牌的相同组件就是创建了不同的主机
- 分离了部件的构造(由Builder来负责)和装配(由Director负责)。从而可以构建出复杂的对象。这个模式适用于:
某个对象的构建过程复杂的情况
。 - 由于实现了构建和装配的解耦。
不同的构建器,相同的装配,也可以做出不同的对象
;相同的构建器,不同的装配顺序也可以做出不同的对象
。也就是实现了构建算法。装配算法的解耦,实现了更好的复用。 建造者模式可以将部件和其组装过程分开,一步步创建一个复杂的对象
。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。
(2).结构
建造者(Builder)模式包含如下角色
- 抽象建造者类(Builder): 这个接口要实现复杂对象的那些部分的创建,并不涉及具体的对象部件的创建。
- 具体建造者类(ConCreteBuilder): 实现Builder接口,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实列。
- 产品类(Product): 要创建的复杂对象。
- 指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在知道者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
(3).实列
创建共享单车
生产自行车是一个复杂的过程,它包含了车架,车座等组件的生产。而车架又有碳纤维,铝合金等材质的,车座有橡胶,真皮等材质。对于自行车的生产就可以使用建造者模式。
这里的Bike是产品,包含车架,车座等组件;Builder是抽象建造者,摩拜单车公司和ofo公司是具体的创建者;Direct是指挥者。
protected:访问权限->本类以及本类的子类。创建对象的i两种方式->有参创造和无参创造。无参创造会回溯到祖宗类Object类,所以不管用哪种方式->我们尽量带上无参构造
- 指挥者和抽象类分离
产品
package com.jsxs.pattern.build.demo1; /** * @Author Jsxs * @Date 2023/4/18 15:40 * @PackageName:com.jsxs.pattern.build.demo1 * @ClassName: Bike * @Description: TODO 具体的产品对象 * @Version 1.0 */ public class Bike { private String frame; //车架 private String seat; //车座 public String getFrame() { return frame; } public void setFrame(String frame) { this.frame = frame; } public String getSeat() { return seat; } public void setSeat(String seat) { this.seat = seat; } }
建造者接口
package com.jsxs.pattern.build.demo1; /** * @Author Jsxs * @Date 2023/4/18 15:42 * @PackageName:com.jsxs.pattern.build.demo1 * @ClassName: Builder * @Description: TODO * @Version 1.0 */ public abstract class Builder { // 1.声明Bike类型的变量 protected Bike bike=new Bike(); // 设计图或者概念-还没组装 public abstract void buildFame(); //车架 public abstract void buildSeat(); //车座 public abstract Bike createBike(); //构建具体自行车的方法 }
具体建造者
package com.jsxs.pattern.build.demo1; /** * @Author Jsxs * @Date 2023/4/18 15:50 * @PackageName:com.jsxs.pattern.build.demo1 * @ClassName: MobileCompany * @Description: TODO 摩拜公司 * @Version 1.0 */ public class MobileCompany extends Builder{ @Override public void buildFame() { bike.setFrame("摩拜-车架"); } @Override public void buildSeat() { bike.setFrame("摩拜-车座"); } @Override public Bike createBike() { return bike; } }
package com.jsxs.pattern.build.demo1; /** * @Author Jsxs * @Date 2023/4/18 15:52 * @PackageName:com.jsxs.pattern.build.demo1 * @ClassName: OfoCompany * @Description: TODO * @Version 1.0 */ public class OfoCompany extends Builder{ @Override public void buildFame() { bike.setFrame("off-车架"); } @Override public void buildSeat() { bike.setSeat("off-车座"); } @Override public Bike createBike() { return bike; } }
指挥者
package com.jsxs.pattern.build.demo1; /** * @Author Jsxs * @Date 2023/4/18 15:55 * @PackageName:com.jsxs.pattern.build.demo1 * @ClassName: Director * @Description: TODO 总工程师-指挥者 * @Version 1.0 */ public class Director { // 声明Builder类型的变量 private Builder builder; // 声明有参构造创建对象 public Director(Builder builder) { this.builder = builder; } // 组装自行车的功能 public Bike construct(){ //构造自行车 this.builder.buildFame(); this.builder.buildSeat(); return builder.createBike(); } }
客户端
package com.jsxs.pattern.build.demo1; /** * @Author Jsxs * @Date 2023/4/18 16:32 * @PackageName:com.jsxs.pattern.build.demo1 * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { Director director = new Director(new MobileCompany()); // 指挥者组装对象 Bike bike = director.construct(); System.out.println(bike.getFrame()); } }
指挥者类Director在建造者模式中很重要,它用于知道具体构建这如何构建产品,控制调用先后次序,并向调用者返回完整的产品类,但是有一些情况需要简化系统结构,可以把指挥者类和抽象类建造者进行结合
- 抽象类和建造者不分离
自行车产品
package com.jsxs.pattern.build.demo1; /** * @Author Jsxs * @Date 2023/4/18 15:40 * @PackageName:com.jsxs.pattern.build.demo1 * @ClassName: Bike * @Description: TODO 具体的产品对象 * @Version 1.0 */ public class Bike { private String frame; //车架 private String seat; //车座 public String getFrame() { return frame; } public void setFrame(String frame) { this.frame = frame; } public String getSeat() { return seat; } public void setSeat(String seat) { this.seat = seat; } }
抽象创建者--- 结合
package com.jsxs.pattern.build.demo1; /** * @Author Jsxs * @Date 2023/4/18 15:42 * @PackageName:com.jsxs.pattern.build.demo1 * @ClassName: Builder * @Description: TODO * @Version 1.0 */ public abstract class Builder { // 1.声明Bike类型的变量 protected Bike bike=new Bike(); // 设计图或者概念-还没组装 public abstract void buildFame(); //车架 public abstract void buildSeat(); //车座 public abstract Bike createBike(); //构建具体自行车的方法 // 组装自行车的功能 public Bike construct(){ //构造自行车 this.buildFame(); this.buildSeat(); return this.createBike(); } }
具体建造者
package com.jsxs.pattern.build.demo1; /** * @Author Jsxs * @Date 2023/4/18 15:50 * @PackageName:com.jsxs.pattern.build.demo1 * @ClassName: MobileCompany * @Description: TODO 摩拜公司 * @Version 1.0 */ public class MobileCompany extends Builder{ @Override public void buildFame() { bike.setFrame("摩拜-车架"); } @Override public void buildSeat() { bike.setFrame("摩拜-车座"); } @Override public Bike createBike() { return bike; } @Override public Bike construct() { return super.construct(); } }
package com.jsxs.pattern.build.demo1; /** * @Author Jsxs * @Date 2023/4/18 15:52 * @PackageName:com.jsxs.pattern.build.demo1 * @ClassName: OfoCompany * @Description: TODO * @Version 1.0 */ public class OfoCompany extends Builder{ @Override public void buildFame() { bike.setFrame("off-车架"); } @Override public void buildSeat() { bike.setSeat("off-车座"); } @Override public Bike createBike() { return bike; } @Override public Bike construct() { return super.construct(); } }
客户端
package com.jsxs.pattern.build.demo1; /** * @Author Jsxs * @Date 2023/4/18 16:32 * @PackageName:com.jsxs.pattern.build.demo1 * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { MobileCompany mobileCompany = new MobileCompany(); Bike bike = mobileCompany.construct(); System.out.println(bike.getFrame()); } }
说明: 这样做确实简化了系统结构,让生产者来构建自行车,但同时也加重了抽象建造者类的职责,也不是太符合单一职责的原则。如果构建自行车contrstuct()这个方法过于复杂,建议还是封装到指挥者中。
(4).优缺点
优点:
建造者模式的封装性很好
。使用建造者模式可以有效地封装变化,在使用建造者模式的场景中,一般产品类和建造这类是比较稳定的,因此,将主要的业务逻辑封装在指挥者类中对整体而言可以取得比较好的稳定性。- 在建造者模式中,客户端不必知道产品内部组成的细节,
将产品与产品的创建过程解耦
,使得相同的创建过程可以创建不同的产品对象。 可以更加精密地控制产品地创建过程
。将复杂产品地创建步骤分解在不同地方法中,使得创建过程更加清晰,也是更方便使用程序来控制创建过程。- 建造者模式很容易进行扩展,通过一个新的建造者类就可以完成,基本上不用修改之前已经测试通过地代码,因此也就不会对原有功能引入风险,符合开闭原则。
缺点:
建造者模式所创建地产品一般具有较多地共同点,其组成部分很相似,如果产品之间地差异性很大,则不适用建造者模式
,因此其实用范围收到一定限制。
(5).使用场景
建造者模式创建地是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在一下场合使用:
- 创建的对象比较复杂,有多个部件构成,
各部件面临着复杂的变化,但构件间的建造顺序是稳定的
。 - 常见复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。