定义
将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
它是将一个复杂的对象分解为多个简答的对象,然后一步一步构建而成。
它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
优缺点
优点
- 封装性号,构建和表示分离。
- 扩展性好,各个具体的建造者相互独立,有利于系统的解耦。
- 客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其他模块产生任何影响,便于控制细节风险。
缺点
- 产品的组成部分必须相同,这限制了其使用范围。
- 如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。
问题
比如我们有一个计算机类,类里面有些属性是必填参数,有些是选填的,那么我们按照传统方式进行创建的话一般有两种方式:
1 2 3 4 5 6 7
| public class Computer { private String cpu; private String ram; private int usbCount; private String keyboard; private String display; }
|
第一种:折叠构造函数模式,通过重写含有不同参数的构造函数进行赋值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class Computer { private String cpu; private String ram; private int usbCount; private String keyboard; private String display;
public Computer(String cpu, String ram) { this(cpu,ram,0); }
public Computer(String cpu, String ram, int usbCount) { this(cpu,ram,usbCount,"罗技键盘"); }
public Computer(String cpu, String ram, int usbCount, String keyboard) { this(cpu,ram,usbCount,keyboard,"三星显示器"); }
public Computer(String cpu, String ram, int usbCount, String keyboard, String display) { this.cpu = cpu; this.ram = ram; this.usbCount = usbCount; this.keyboard = keyboard; this.display = display; } }
|
第二种:Javabean模式,通过使用set方法进行赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Computer { private String cpu; private String ram; private int usbCount; private String keyboard; private String display; public void setCpu(String cpu) { this.cpu = cpu; } public void setRam(String ram) { this.ram = ram; } public void setUsbCount(int usbCount) { this.usbCount = usbCount; } public void setKeyboard(String keyboard) { this.keyboard = keyboard; } public void setDisplay(String display) { this.display = display; } }
|
弊端
第一种主要是使用及阅读不方便,当你想要使用一个类的构造函数的时候,你首先要想清楚自己需要使用哪一个,然后还要搞清楚这个函数里面参数的含义,很容易混淆。
第二种主要是在构建类的过程中是分两步进行的,这个操作容易导致操作失误,出现问题。
建造者模式代码实现
结构组成
- 产品角色:它是包含多个组成部件的复杂对象,由具体创建者来创建其各个零部件。
- 抽象建造者:它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品方法的getResult()。
- 具体建造者:实现Builder接口,完成复杂产品的各个部件的具体创建方法。
- 指挥者:它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
第一种实现:
首先创建目标类,也就是我们的产品角色,要实现的产品定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
public class Computer { private String cpu; private String ram; private int usbCount; private String keyboard; private String display;
public Computer(String cpu, String ram) { this.cpu = cpu; this.ram = ram; }
public void setUsbCount(int usbCount) { this.usbCount = usbCount; }
public void setKeyboard(String keyboard) { this.keyboard = keyboard; }
public void setDisplay(String display) { this.display = display; }
@Override public String toString() { return "Computer{" + "cpu='" + cpu + '\'' + ", ram='" + ram + '\'' + ", usbCount=" + usbCount + ", keyboard='" + keyboard + '\'' + ", display='" + display + '\'' + '}'; } }
|
然后创建抽象建造者,对具体建造实现类的一个抽象
1 2 3 4 5 6 7 8 9 10 11 12
|
public abstract class ComputerBuilder {
public abstract void getUsbCount(); public abstract void getKeyboard(); public abstract void getDisplay();
public abstract Computer getComputer();
}
|
指挥者负责创建流程
1 2 3 4 5 6 7 8 9 10
|
public class ComputerDirector { public void makeComputer(ComputerBuilder builder) { builder.getKeyboard(); builder.getDisplay(); builder.getUsbCount(); } }
|
具体建造者,建造者的具体实现,创建产品对象,定义具体产品的创建规则,这已创建电脑举例
华硕电脑创建者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
public class AsusComputerBuilder extends ComputerBuilder {
private Computer computer;
public AsusComputerBuilder(String cpu, String ram) { computer = new Computer(cpu, ram); }
@Override public void getUsbCount() { computer.setUsbCount(2); }
@Override public void getKeyboard() { computer.setKeyboard("华硕键盘"); }
@Override public void getDisplay() { computer.setDisplay("华硕显示器"); }
@Override public Computer getComputer() { return computer; } }
|
联想电脑建造者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
public class LenovoComputerBuilder extends ComputerBuilder {
private Computer computer;
public LenovoComputerBuilder(String cpu, String ram) { computer = new Computer(cpu, ram); }
@Override public void getUsbCount() { computer.setUsbCount(2); }
@Override public void getKeyboard() { computer.setKeyboard("联想键盘"); }
@Override public void getDisplay() { computer.setDisplay("联想显示器"); }
@Override public Computer getComputer() { return computer; } }
|
具体调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Test {
public static void main(String[] args) { ComputerDirector director = new ComputerDirector();
ComputerBuilder asusBuilder = new AsusComputerBuilder("英特尔i7","金士顿"); director.makeComputer(asusBuilder); Computer asusComputer = asusBuilder.getComputer(); System.out.println(asusComputer);
ComputerBuilder lenovoBuilder = new LenovoComputerBuilder("英特尔i8","三星"); director.makeComputer(lenovoBuilder); Computer lenovoComputer = lenovoBuilder.getComputer(); System.out.println(lenovoComputer); }
}
|
第一种方法UML类图
第二种方法:
在Computer
类中创建一个静态内部类ComputerBuilder
,ComputerBuilder
类的属性和Computer
类相同,在ComputerBuilder
类中创建设置函数,函数的返回类型为ComputerBuilder
类型,通过设置函数对可选参数进行赋值,也可以把必选参数也用设置函数赋值,不过这里使用了
有参构造进行赋值,创建一个build()
方法用来在ComputerBuilder
中构建Computer
实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| public class Computer { private String cpu; private String ram; private int usbCount; private String keyboard; private String display;
public Computer(ComputerBuilder computerBuilder) { this.cpu = computerBuilder.cpu; this.ram = computerBuilder.ram; this.usbCount = computerBuilder.usbCount; this.keyboard = computerBuilder.keyboard; this.display = computerBuilder.display; }
public static class ComputerBuilder{ private String cpu; private String ram; private int usbCount; private String keyboard; private String display;
public ComputerBuilder(String cpu, String ram) { this.cpu = cpu; this.ram = ram; } public ComputerBuilder setUsbCount(int usbCount) { this.usbCount = usbCount; return this; } public ComputerBuilder setKeyboard(String keyboard) { this.keyboard = keyboard; return this; } public ComputerBuilder setDisplay(String display) { this.display = display; return this; } public Computer build() { return new Computer(this); } } @Override public String toString() { return "Computer{" + "cpu='" + cpu + '\'' + ", ram='" + ram + '\'' + ", usbCount=" + usbCount + ", keyboard='" + keyboard + '\'' + ", display='" + display + '\'' + '}'; } }
|
第二种方法UML类图