尺有所短,寸有所长;不忘初心,方得始终。
一、建造者模式是什么
建造者模式是一种创建型设计模式,能够分步骤创建复杂对象。该模式允许使用相同的创建代码生成不同类型和形式的对象。
最大的特点就是能够让我们分步创建对象
主要作用:将一个复杂的构建进行分离拆分,使得同样的构建过程可以创建不同的表示。
主要解决:创建由各个部分的子对象用一定的算法构成的复杂对象。
何时使用:一些基本部件不会变,而其组合经常变化的时候。
如何解决:将变与不变分离开。
关键代码:建造者:创建和提供实例,主管:管理建造出来的实例的依赖关系。
二、建造者模式的适用场景
-
创建的对象具有复杂的内部结构以及对象组成算法独立。
-
创建的对象内部属性本身相互依赖。
比如:造汽车,无论是什么牌子的汽车都好包含轮胎,发动机、底盘、变速箱、车身等独立子对象组成。这些子对象组合起来才是一个完整的汽车对象
三、建造者模式结构
-
建造者 (Builder):声明一个接口或抽象类作为抽象建造者,便于扩展,在抽象建造者中声明生成器中通用的产品构造步骤。(一般至少包含一个建造产品的抽象方法,一个是返回产品的抽象方法)
-
具体建造者 (Concrete Builders) :为抽象建造者提供构造对象过程的不同实现。具体生成器也可以构造不遵循通用接口的产品。
-
指挥者 (Director) :定义调用构造步骤的顺序, 创建和复用特定的产品配置。
-
产品 (Products) :由不同生成器最终构造的对象。
-
客户端 (Client) 必须将某个生成器对象与主管类关联,使用生成器对象完成后续所有的构造任务。
四、建造者模式实现方式
-
声明产品类,确定产品属性组成。
-
声明一个接口或抽象类作为抽象建造者,定义一个返回产品的抽象方法,以及建造产品所需要的抽象方法。
-
为每个形式的产品创建具体建造者类, 并实现其构造步骤。
-
声明指挥者类,它可以使用同一生成器对象来封装多种构造产品的方式。
-
在客户端代码会同时创建生成器和主管对象,将生成器对象传递给主管对象进行关联
只有在所有产品都遵循相同接口的情况下, 构造结果可以直接通过主管类获取。否则客户端应当通过生成器获取构造结果。
五、建造者模式的实现
案例:造汽车,汽车对象由轮胎,发动机、底盘、变速箱、车身五个独立子对象组成。
-
具体产品
package com.edwin.design.upupdesign.builder;
/**
* 汽车
*/
public class Car {
/**
* 轮胎
*/
public String tire;
/**
* 发动机
*/
public String engine;
/**
* 底盘
*/
public String chassis;
/**
* 变速箱
*/
public String gearbox;
/**
* 车身
*/
public String body;
......get set 方法省略........
} -
抽象建造者
package com.edwin.design.upupdesign.builder;
/**
* 抽象建造者 : 声明生成器中通用的产品构造步骤
*/
public abstract class 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();
}
-
具体建造者
/**
* 具体建造者 :客车建造者
*/
public class 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;
}
}
/**
* 具体建造者 :越野车建造者
*/
public class 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;
}
} -
指挥者
/**
* 指挥者 :定义调用构造步骤的顺序, 创建和复用特定的产品配置。
*/
public class 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));
} -
案例输出结果
六、建造者模式的优缺点
-
优点
-
客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
-
每一个具体建造者都独立,可以方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象 。
-
增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合开闭原则。
-
缺点
-
当建造者过多时,会产生很多类,难以维护。
-
产品必须有共同点,范围有限制
-
若产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
七、建造者模式和工厂模式的区别
-
工厂模式用于处理 如何获取实例对象,建造者模式用于处理如何建造实例对象 。
-
建造者模式比工厂模式多了一个指挥者 的角色,如果把指挥者的逻辑放在客户端,那么建造者模式剩余的部分就可以看作是一个简单的工厂模式。
-
职责不同:
-
建造者模式中的建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给指挥类。由指挥类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端 -
工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品
八、总结
建造者模式的使用场合是当创建复杂对象时,把创建对象成员和装配方法分离出来,放在建造者类中去实现,客户端使用该复杂对象时,不用理会它的创建和装配过程,只关心它的表示形式。
原文始发于微信公众号(星河之码):设计模式(6):建造者模式
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/27187.html