目录
一、建造者模式是什么
构建者(建造者)模式(构造器模式和建造者模式)
建造者模式是一种创建型设计模式,能够分步骤创建复杂对象。该模式允许使用相同的创建代码生成不同类型和形式的对象。
最大的特点就是能够让我们分步创建对象
主要作用:将一个复杂的构建进行分离拆分,使得同样的构建过程可以创建不同的表示。
主要解决:创建由各个部分的子对象用一定的算法构成的复杂对象。
何时使用:一些基本部件不会变,而其组合经常变化的时候。
如何解决:将变与不变分离开。
关键代码:建造者:创建和提供实例,主管:管理建造出来的实例的依赖关系。
二、建造者模式的适用场景
-
创建的对象具有复杂的内部结构以及对象组成算法独立。
-
创建的对象内部属性本身相互依赖。
比如:造汽车,无论是什么牌子的汽车都好包含轮胎,发动机、底盘、变速箱、车身等独立子对象组成。这些子对象组合起来才是一个完整的汽车对象
三、建造者模式结构
-
建造者 (Builder):声明一个接口或抽象类作为抽象建造者,便于扩展,在抽象建造者中声明生成器中通用的产品构造步骤。(一般至少包含一个建造产品的抽象方法,一个是返回产品的抽象方法)
-
具体建造者 (Concrete Builders) :为抽象建造者提供构造对象过程的不同实现。具体生成器也可以构造不遵循通用接口的产品。
-
指挥者 (Director) :定义调用构造步骤的顺序, 创建和复用特定的产品配置。
-
产品 (Products) :由不同生成器最终构造的对象。
-
客户端 (Client) 必须将某个生成器对象与主管类关联,使用生成器对象完成后续所有的构造任务。
建造者模式要解决的问题:建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无需知道其内部的具体构造细节。
比如:一辆汽车是由多个部件组成的,包括了车轮、方向盘、发动机等等。对于大多数用户而言,并不需要知道这些部件的装配细节,并且几乎不会使用单独某个部件,而是使用一辆完整的汽车。而建造者模式就是负责将这些部件进行组装然后将完整的汽车返回给用户。
四、建造者模式实现方式
-
声明产品类,确定产品属性组成。
-
声明一个接口或抽象类作为抽象建造者,定义一个返回产品的抽象方法,以及建造产品所需要的抽象方法。
-
为每个形式的产品创建具体建造者类, 并实现其构造步骤。
-
声明指挥者类,它可以使用同一生成器对象来封装多种构造产品的方式。
-
在客户端代码会同时创建生成器和主管对象,将生成器对象传递给主管对象进行关联
只有在所有产品都遵循相同接口的情况下, 构造结果可以直接通过主管类获取。否则客户端应当通过生成器获取构造结果。
五、建造者模式的实现
案例:造汽车,汽车对象由轮胎,发动机、底盘、变速箱、车身五个独立子对象组成。
-
具体产品
package com.edwin.design.upupdesign.builder; /** * 汽车 */ publicclass Car { /** * 轮胎 */ public String tire; /** * 发动机 */ public String engine; /** * 底盘 */ public String chassis; /** * 变速箱 */ public String gearbox; /** * 车身 */ public String body; ......get set 方法省略........ }
-
抽象建造者
package com.edwin.design.upupdesign.builder; /** * 抽象建造者 : 声明生成器中通用的产品构造步骤 */ publicabstractclass Builder { /** * 生产轮胎 */ public abstract void tire(); /** * 生产发动机 */ public abstract void engine(); /** * 生产底盘 */ public abstract void chassis(); /** * 生产变速箱 */ public abstract void gearbox(); /** * 生产车身 */ public abstract void body(); /** * 返回产品的抽象方法 */ public abstract Car getResult(); }
-
具体建造者
/** * 具体建造者 :客车建造者 */ publicclass BusBuilder extends Builder{ private Car car = new Car(); @Override public void tire() { car.setTire("客车的黑色轮胎"); } @Override public void engine() { car.setEngine("客车的发动机"); } @Override public void chassis() { car.setChassis("客车的底盘"); } @Override public void gearbox() { car.setGearbox("客车的变速箱"); } @Override public void body() { car.setBody("客车的车身"); } @Override public Car getResult() { return car; } } /** * 具体建造者 :越野车建造者 */ publicclass SuvBuilder extends Builder{ private Car car = new Car(); @Override public void tire() { car.setTire("越野车的黑色轮胎"); } @Override public void engine() { car.setEngine("越野车的发动机"); } @Override public void chassis() { car.setChassis("越野车的底盘"); } @Override public void gearbox() { car.setGearbox("越野车的变速箱"); } @Override public void body() { car.setBody("越野车的车身"); } @Override public Car getResult() { return car; } }
-
指挥者
/** * 指挥者 :定义调用构造步骤的顺序, 创建和复用特定的产品配置。 */ publicclass Director { public void construct(Builder builder){ //定义车子的生产顺序 或者在生产过程中添加其他业务逻辑 builder.tire(); builder.body(); builder.chassis(); builder.engine(); builder.gearbox(); } }
-
客户端
public static void main(String[] args) throws Exception { Director director = new Director(); Builder busBuilder = new BusBuilder(); //指挥者用busBuilder方法建造客车 director.construct(busBuilder); Car busCar = busBuilder.getResult(); System.out.println("----构建的客车对象===>>> :" + JSONObject.toJSON(busCar)); //指挥者用SuvBuilder方法建造越野车 Builder suvBuilder = new SuvBuilder(); director.construct(suvBuilder); Car suvCar = suvBuilder.getResult(); System.out.println("----构建的越野车对象===>>> :" + JSONObject.toJSON(suvCar)); }
-
案例输出结果
六、建造者模式的优缺点
-
优点
-
客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
-
每一个具体建造者都独立,可以方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象 。
-
增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合开闭原则。
-
-
缺点
-
当建造者过多时,会产生很多类,难以维护。
-
产品必须有共同点,范围有限制
-
若产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
-
七、建造者模式和工厂模式的区别
-
工厂模式用于处理 如何获取实例对象,建造者模式用于处理如何建造实例对象 。
-
建造者模式比工厂模式多了一个指挥者 的角色,如果把指挥者的逻辑放在客户端,那么建造者模式剩余的部分就可以看作是一个简单的工厂模式。
-
职责不同:
-
建造者模式中的建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给指挥类。由指挥类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端
-
工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品
-
八、总结
建造者模式的使用场合是当创建复杂对象时,把创建对象成员和装配方法分离出来,放在建造者类中去实现,客户端使用该复杂对象时,不用理会它的创建和装配过程,只关心它的表示形式。