概述
将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。
1、分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况。
2、 由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象;相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦,实现了更好的复用。
3、 建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。
结构
建造者(Builder)模式包含如下角色:
1、抽象建造者类(Builder):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的部件对象的创建。
2、具体建造者类(ConcreteBuilder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实例。
3、产品类(Product):要创建的复杂对象。
4、指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
类图如下:
实例
创建共享单车
生产自行车是一个复杂的过程,它包含了车架,车座等组件的生产。而车架又有碳纤维,铝合金等材质 的,车座有橡胶,真皮等材质。对于自行车的生产就可以使用建造者模式。
这里Bike是产品,包含车架,车座等组件;Builder是抽象建造者,MobikeBuilder和 OfoBuilder是具体的建造者;Director是指挥者。
类图如下:
代码实现
/**
* @author: xuzhilei
* @create: 2021-12-29
* @description: 自行车类
**/
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;
}
}
/**
* @author: xuzhilei
* @create: 2021-12-29
* @description: 抽象建造者类
**/
public abstract class Builder {
protected Bike mBike;
/**
* 组装车架
*/
abstract void buildFrame();
/**
* 组装车座
*/
abstract void buildSeat();
/**
* 建造自行车
* @return 返回自行车对象
*/
abstract Bike createBike();
}
/**
* @author: xuzhilei
* @create: 2021-12-29
* @description: 摩拜自行车建造者类
**/
public class MobikeBuilder extends Builder{
public MobikeBuilder(Bike bike) {
this.mBike = bike;
}
@Override
void buildFrame() {
mBike.setFrame("铝合金车架");
}
@Override
void buildSeat() {
mBike.setSeat("真皮车座");
}
@Override
Bike createBike() {
return mBike;
}
}
/**
* @author: xuzhilei
* @create: 2021-12-29
* @description: ofo自行车建造者类
**/
public class OfoBuilder extends Builder{
public OfoBuilder(Bike bike){
this.mBike = bike;
}
@Override
void buildFrame() {
mBike.setFrame("碳纤维车架");
}
@Override
void buildSeat() {
mBike.setSeat("橡胶车座");
}
@Override
Bike createBike() {
return mBike;
}
}
/**
* @author: xuzhilei
* @create: 2021-12-29
* @description: 指挥者类
**/
public class Director {
private Builder builder;
public void setBuilder(Builder builder){
this.builder = builder;
}
public Builder getBuilder() {
return builder;
}
/**
* 指挥建造者类组装自行车的方法
* @return 具体的自行车对象
*/
public Bike construct(){
builder.buildFrame();
builder.buildSeat();
return builder.createBike();
}
}
/**
* @author: xuzhilei
* @create: 2021-12-29
* @description: 模拟建造自行车
**/
public class Client {
public static void main(String[] args) {
//创建指挥者对象
Director director = new Director();
//创建未具体化的自行车对象
Bike bike = new Bike();
//摩拜自行车建造者对象
MobikeBuilder mobikeBuilder = new MobikeBuilder(bike);
//注入建造者对象对象
director.setBuilder(mobikeBuilder);
//组装自行车,得到具体的自行车对象
Bike moBike = director.construct();
System.out.println("摩拜自行车的车架" + moBike.getFrame());
System.out.println("摩拜自行车的车座" + moBike.getSeat());
//创建ofo自行车建造者对象
OfoBuilder ofoBuilder = new OfoBuilder(bike);
director.setBuilder(ofoBuilder);
Bike ofoBike = director.construct();
System.out.println("ofo自行车的车架" + ofoBike.getFrame());
System.out.println("ofo自行车的车座" + ofoBike.getSeat());
}
}
测试结果:
注意: 上面示例是 Builder模式的常规用法,指挥者类 Director 在建造者模式中具有很重要的作用,它 用于指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类,但是有些情况 下需要简化系统结构,可以把指挥者类和抽象建造者进行结合
/**
* @author: xuzhilei
* @create: 2021-12-29
* @description: 抽象建造者类
**/
public abstract class Builder {
protected Bike mBike;
/**
* 组装车架
*/
abstract void buildFrame();
/**
* 组装车座
*/
abstract void buildSeat();
/**
* 建造自行车
* @return 返回自行车对象
*/
abstract Bike createBike();
/**
* 组装自行车
* @return 具体的自行车对象
*/
public Bike construct(){
this.buildFrame();
this.buildSeat();
return this.createBike();
}
}
/**
* @author: xuzhilei
* @create: 2021-12-29
* @description: 模拟建造自行车
**/
public class Client {
public static void main(String[] args) {
//创建未具体化的自行车对象
Bike bike = new Bike();
//摩拜自行车建造者对象
MobikeBuilder mobikeBuilder = new MobikeBuilder(bike);
//组装自行车,得到具体的自行车对象
Bike moBike = mobikeBuilder.construct();
System.out.println("摩拜自行车的车架" + moBike.getFrame());
System.out.println("摩拜自行车的车座" + moBike.getSeat());
//创建ofo自行车建造者对象
OfoBuilder ofoBuilder = new OfoBuilder(bike);
Bike ofoBike = ofoBuilder.construct();
System.out.println("ofo自行车的车架" + ofoBike.getFrame());
System.out.println("ofo自行车的车座" + ofoBike.getSeat());
}
}
测试结果:
分析: 这样做确实简化了系统结构,但同时也加重了抽象建造者类的职责,也不是太符合单一职责原则,如果 construct() 过于复杂,建议还是封装到 Director 中。
模式扩展
建造者模式除了上面的用途外,在开发中还有一个常用的使用方式,就是当一个类构造器需要传入很多 参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者 模式进行重构。
重构前代码如下:
/**
* @author: xuzhilei
* @create: 2021-12-29
* @description: 手机类
**/
public class Phone {
/**
* cpu
*/
private String cpu;
/**
* 屏幕
*/
private String screen;
/**
* 内存
*/
private String memory;
/**
* 主板
*/
private String mainBoard;
public Phone(String cpu, String screen, String memory, String mainBoard) {
this.cpu = cpu;
this.screen = screen;
this.memory = memory;
this.mainBoard = mainBoard;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getScreen() {
return screen;
}
public void setScreen(String screen) {
this.screen = screen;
}
public String getMemory() {
return memory;
}
public void setMemory(String memory) {
this.memory = memory;
}
public String getMainBoard() {
return mainBoard;
}
public void setMainBoard(String mainBoard) {
this.mainBoard = mainBoard;
}
@Override
public String toString() {
return "Phone{" +
"cpu='" + cpu + '\'' +
", screen='" + screen + '\'' +
", memory='" + memory + '\'' +
", mainBoard='" + mainBoard + '\'' +
'}';
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
//构造手机对象
Phone phone = new Phone("麒麟980", "4K", "128G", "华为");
System.out.println(phone);
}
}
上面在测试方法中构建Phone对象,传递了四个参数,如果参数更多呢?代码的可读性及使用的成本 就是比较高。
重构代码后:
/**
* @author: xuzhilei
* @create: 2021-12-29
* @description: 使用建造模式思想优化后的手机类
**/
public class NewPhone {
/**
* cpu
*/
private String cpu;
/**
* 屏幕
*/
private String screen;
/**
* 内存
*/
private String memory;
/**
* 主板
*/
private String mainBoard;
/**
* 手机类私有构造器
* @param builder 内部建造者类对象
*/
private NewPhone(Builder builder){
this.cpu = builder.cpu;
this.screen = builder.screen;
this.memory = builder.memory;
this.mainBoard = builder.mainBoard;
}
/**
* 内部建造者类
*/
public static class Builder{
private String cpu;
private String screen;
private String memory;
private String mainBoard;
public Builder(){
}
//设置cpu
public Builder cpu(String cpu){
this.cpu = cpu;
return this;
}
//设置屏幕
public Builder screen(String screen){
this.screen = screen;
return this;
}
//设置内存
public Builder memory(String memory){
this.memory = memory;
return this;
}
//设置主板
public Builder mainBoard(String mainBoard){
this.mainBoard = mainBoard;
return this;
}
//构造手机对象
public NewPhone build(){
return new NewPhone(this);
}
}
@Override
public String toString() {
return "NewPhone{" +
"cpu='" + cpu + '\'' +
", screen='" + screen + '\'' +
", memory='" + memory + '\'' +
", mainBoard='" + mainBoard + '\'' +
'}';
}
}
/**
* @author: xuzhilei
* @create: 2021-12-29
* @description: 测试类
**/
public class Client {
public static void main(String[] args) {
NewPhone newPhone = new NewPhone.Builder()
.cpu("麒麟880")
.screen("2K")
.memory("64G")
.mainBoard("华为")
.build();
System.out.println(newPhone);
}
}
重构后的代码在使用起来更方便,可读性更好,某种程度上也可以提高开发效率。
以上是个人随手敲的demo,如有不正确的地方,可以在下方留言指正,谢谢。与各位优快云的伙伴们共勉,每天记录一点点,每天进步一点点