建造者模式属于设计模式中构建模式这一大类,主要用途是用来创建复杂的复合对象,可以替代构造方法,进行灵活搭配,简单点来理解就是高配,中配,低配,想配哪种配哪种。
定义:指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示
我们结合一个简单的例子实操一下,假设我们要组装一台电脑:
public class Computer {
/**CPU*/
private String cpu;
/**主板*/
private String mainBoard;
/**光驱*/
private String drive;
/**硬盘*/
private String hardDisk;
/**内存*/
private String memory;
/**带光驱版*/
public Computer(String cpu,String mainBoard,String drive,String hardDisk,String memory){
this.cpu = cpu;
this.mainBoard = mainBoard;
this.drive = drive;
this.hardDisk = hardDisk;
this.memory = memory;
}
/**不带光驱版*/
public Computer(String cpu,String mainBoard,String hardDisk,String memory){
this.cpu = cpu;
this.mainBoard = mainBoard;
this.hardDisk = hardDisk;
this.memory = memory;
}
}
从上面的代码应该能看出,每加一种新的组装电脑的方式,我们都可能需要再加一个构造方法来实现。
下面我们用一个稍微简单一点的建造者模式重构一下:
public class Computer {
/**CPU*/
private String cpu;
/**主板*/
private String mainBoard;
/**光驱*/
private String drive;
/**硬盘*/
private String hardDisk;
/**内存*/
private String memory;
/**带光驱版*/
public Computer(Builder builder){
this.cpu = builder.cpu;
this.mainBoard = builder.mainBoard;
this.drive = builder.drive;
this.hardDisk = builder.hardDisk;
this.memory = builder.memory;
}
public static final class Builder{
/**CPU*/
private String cpu;
/**主板*/
private String mainBoard;
/**光驱*/
private String drive;
/**硬盘*/
private String hardDisk;
/**内存*/
private String memory;
public Builder cpu(String cpu){
this.cpu = cpu;
return this;
}
public Builder mainBoard(String mainBoard){
this.mainBoard = mainBoard;
return this;
}
public Builder drive(String drive){
this.drive = drive;
return this;
}
public Builder hardDisk(String hardDisk){
this.hardDisk = hardDisk;
return this;
}
public Builder memory(String memory){
this.memory = memory;
return this;
}
public Computer build(){
return new Computer(this);
}
}
}
这样我们就可以按如下非常灵活的方式来构建:
Computer computer = new Computer.Builder()
.memory("DDR3")
.mainBoard("AMD")
.drive("DELL")
.build();
如果我们不需要光驱,只需要去掉构建光驱的步骤就行了。
要构造更复杂一点的对象,我们再来看一看完整建造者模式的uml类图:
根据上图来理解建造者模式包含的角色:
抽象建造者类(Builder):接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的部件对象的创建。
具体建造者类(ConcreteBuilder):实现Builder接口,完成复杂产品的各个部件的具体创建方法。在构建过程完成后,创建产品实例。
产品类(Product):要创建的复杂对象
指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
我们再来看一个相对更复杂一点例子:
//产品角色:包含多个组成部件的复杂对象。
class Product {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
public void setPartC(String partC) {
this.partC = partC;
}
public void show() {
//显示产品的特性
}
}
//抽象建造者:包含创建产品各个子部件的抽象方法。
abstract class Builder {
//创建产品对象
protected Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
//返回产品对象
public Product getResult() {
return product;
}
}
//具体建造者:实现了抽象建造者接口。
public class ConcreteBuilder extends Builder {
public void buildPartA() {
product.setPartA("建造 PartA");
}
public void buildPartB() {
product.setPartB("建造 PartB");
}
public void buildPartC() {
product.setPartC("建造 PartC");
}
}
//指挥者:调用建造者中的方法完成复杂对象的创建。
class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
//产品构建与组装方法
public Product construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
}
//测试
public class Client {
public static void main(String[] args) {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
Product product = director.construct();
product.show();
}
}
建造者模式的优点和缺点
优点:
封装性好,构建和表示分离。一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在指挥者类中对整体而言可以取得比较好的稳定性。
扩展性好,各个具体的建造者相互独立,有利于系统的解耦。产品本身与产品的创建过程解耦,相同的创建过程可以创建不同的产品对象。
客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。
缺点:
产品的组成部分必须相同,限制了其使用范围。如果产品之间的差异性很大,则不适合使用建造者模式
如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,会增加维护成本。
应用场景:
相同的方法,不同的执行顺序,产生不同的结果。
多个部件或零件,都可以装配到一个对象中,但是产生的结果又不相同。
产品类非常复杂,或者产品类中不同的调用顺序产生不同的作用。
初始化一个对象特别复杂,参数多,而且很多参数都具有默认值。