概念
建造者模式是一种创建型设计模式,用于创建复杂对象。它的主要目的是将构建复杂对象的过程与其表示相分离,以便同样的构建过程可以创建不同的表示。
在建造者模式中,通常有两个主要角色:建造者(Builder)和指挥者(Director)。建造者负责定义构建复杂对象的各个部分的接口,并实现具体的构建过程;而指挥者则负责协调建造者的工作,按照特定的顺序来实施构建过程。
建造者模式的核心思想是将复杂对象的构建过程分解为一系列简单的步骤,在每个步骤中逐步构建对象的不同部分,最终完成整个对象的构建。通过这种方式,我们可以灵活地组合和构建不同的对象,而不需要直接修改它们的代码。
● Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
●ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
●Product(产品角色):相当于实体类,它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
● Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
示例
产品类(实体类):
/**
* 产品类
* 复杂对象的实体类
* */
public class Computer {
private String cpu;
private String memory;
private String hardDisk;
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getMemory() {
return memory;
}
public void setMemory(String memory) {
this.memory = memory;
}
public String getHardDisk() {
return hardDisk;
}
public void setHardDisk(String hardDisk) {
this.hardDisk = hardDisk;
}
}
建造者抽象类:
/**
* 计算机抽象建造者
* 各个具体的建造者类集成此类,并分别bulid各个部件
* */
public abstract class ComputerBulider {
//直接创建实体类--产品类
Computer computer = new Computer();
public abstract void bulidCpu();
public abstract void bulidMemory();
public abstract void bulidHardDisk();
//工厂方法,返回一个完整的计算机对象
public Computer createComputer() {
return computer;
}
}
建造者具体实现类
/**
* 华硕具体建造者
* 分别bulid各个部件
* */
public class ASUSComputerBulider extends ComputerBulider{
//使用父类已经new好的类,直接在这里赋值
@Override
public void bulidCpu() {
computer.setCpu("酷睿i5");
}
@Override
public void bulidMemory() {
computer.setMemory("16G");
};
@Override
public void bulidHardDisk() {
computer.setHardDisk("1T");
}
}
/**
* 联想具体建造者
* 分别bulid各个部件
* */
public class LenovoComputerBulider extends ComputerBulider{
//使用父类已经new好的类,直接在这里赋值
@Override
public void bulidCpu() {
computer.setCpu("酷睿i7");
}
@Override
public void bulidMemory() {
computer.setMemory("32G");
};
@Override
public void bulidHardDisk() {
computer.setHardDisk("2T");
}
}
指挥者:
/**
* 计算机生产控制器
* 专门给客户端使用,客户端只需要传入某个计算机品牌的建造者类,即可创建并返回该品牌的电脑
* */
public class ComputerController {
//逐步构建复杂产品对象
public Computer construct(ComputerBulider cb) {
Computer computer;
cb.bulidCpu();
cb.bulidMemory();
cb.bulidHardDisk();
computer = cb.createComputer();
return computer;
}
}
客户端:
ComputerController controller = new ComputerController();
//构造华硕电脑
ComputerBulider bulider = new ASUSComputerBulider();
Computer ASUSComputer = controller.construct(bulider);
System.out.println("华硕电脑CPU型号为:" + ASUSComputer.getCpu() +
",内存大小为:" + ASUSComputer.getMemory() +
",硬盘大小为:" + ASUSComputer.getHardDisk());
//构造华为电脑
ComputerBulider bulider2 = new LenovoComputerBulider();
Computer LenovoComputer = controller.construct(bulider2);
System.out.println("联想电脑CPU型号为:" + LenovoComputer.getCpu() +
",内存大小为:" + LenovoComputer.getMemory() +
",硬盘大小为:" + LenovoComputer.getHardDisk());
输出结果为:
华硕电脑CPU型号为:酷睿i5,内存大小为:16G,硬盘大小为:1T
联想电脑CPU型号为:酷睿i7,内存大小为:32G,硬盘大小为:2T
指挥者高级用法
1、将指挥者与抽象建造者合并,这样就可以省略指挥者
/**
* 计算机抽象建造者
* 各个具体的建造者类集成此类,并分别bulid各个部件
* */
public abstract class ComputerBuliderNew {
//直接创建实体类--产品类
protected static Computer computer = new Computer();
public abstract void bulidCpu();
public abstract void bulidMemory();
public abstract void bulidHardDisk();
//有参方法构建,返回一个完整的计算机对象
public static Computer createComputer(ComputerBuliderNew cbn) {
cbn.bulidCpu();
cbn.bulidMemory();
cbn.bulidHardDisk();
return computer;
}
//无参方法构建,返回一个完整的计算机对象
public Computer createComputer2() {
this.bulidCpu();
this.bulidMemory();
this.bulidHardDisk();
return computer;
}
}
2、我们可以使用钩子函数来精细化控制指挥者的创建过程,比如在电脑配件中,我们要判断是否为独显
/**
* 计算机抽象建造者
* 各个具体的建造者类集成此类,并分别bulid各个部件
* */
public abstract class ComputerBulider {
//直接创建实体类--产品类
Computer computer = new Computer();
public abstract void bulidCpu();
public abstract void bulidMemory();
public abstract void bulidHardDisk();
//钩子方法(是否为机械硬盘)
public boolean isHardDiskDrive() {
return false;
}
//工厂方法,返回一个完整的计算机对象
public Computer createComputer() {
return computer;
}
}
我们可以在具体建造者中覆写这个钩子函数
/**
* 联想具体建造者
* 分别bulid各个部件
* */
public class LenovoComputerBulider extends ComputerBulider{
//使用父类已经new好的类,直接在这里赋值
@Override
public void bulidCpu() {
computer.setCpu("酷睿i7");
}
@Override
public void bulidMemory() {
computer.setMemory("32G");
};
@Override
public void bulidHardDisk() {
computer.setHardDisk("2T");
}
//钩子方法(是否为机械硬盘)
@Override
public boolean isHardDiskDrive() {
return true;
}
}
接下来,接下来在指挥者的构建过程中,可以通过此方法来判断
/**
* 计算机生产控制器
* 专门给客户端使用,客户端只需要传入某个计算机品牌的建造者类,即可创建并返回该品牌的电脑
* */
public class ComputerController {
//逐步构建复杂产品对象
public Computer construct(ComputerBulider cb) {
Computer computer;
cb.bulidCpu();
cb.bulidMemory();
//通过钩子函数来判断是否为机械硬盘,如果不是机械硬盘,则不构建硬盘
if (cb.isHardDiskDrive()) {
cb.bulidHardDisk();
}
computer = cb.createComputer();
return computer;
}
}
总结
我们可以通过建造者模式,通过指挥者来创建复杂的对象,并且在构建过程中一步一步来构建此对象,此外我们引入了钩子函数,利用此函数,可以更加精细化构建过程。
优点:
1、封装性好:通过使用建造者模式,客户端代码只需关注指定需要的产品类型和建造步骤,而不必知道具体的建造细节。
2、可扩展性强:可以增加新的建造者类,扩展产品的种类,且原有的代码无需修改。
容易控制产品的构造过程:由于建造者负责对象构建的每一步骤,因此可以对构建过程逐步细化,并且更容易控制。
3、遵循单一职责原则:将产品的构建过程封装在建造者中,每个建造者类只关注一个具体产品的构建,符合单一职责原则。
缺点:
1、增加了代码量:建造者模式通常需要定义多个类,包括抽象建造者、具体建造者和产品类,可能会增加一些代码量。
2、对象构建过程有序化:由于建造者模式要求按照一定的顺序逐步构建产品,在某些情况下可能会限制部分灵活性。
3、适用范围有限:建造者模式适用于构建复杂对象,如果产品结构简单,可以直接使用其他创建型模式,如工厂方法模式。
建造者模式适用于以下情况:
1、当创建一个对象的构建过程比较复杂,需要进行多个步骤的时候。
2、当需要创建的对象具有多个部分,并且这些部分之间存在一定的组合关系。
3、当希望构建过程能够灵活地组合和复用,以创建不同表示的对象。
总结起来,建造者模式通过将复杂对象的构建过程分解为简单的步骤,并通过指挥者来协调这些步骤的执行,实现了对象的构建与表示的分离,提高了代码的可读性和灵活性,并且易于扩展和维护。但需要注意在选择使用建造者模式时要权衡其优缺点,确保其适用于当前的项目需求。