Builder Pattern: 将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示. 建造者模式是一种对象创建型模式.
关键词: 构建过程, 表示
UML
图示说明:
- Client 到 Director 为 实线普通箭头, 表示拥有
- Client 到 ConcreateBuilder 为 虚线普通箭头, 表示使用关系, Java 中表现为局部变量
- Director 到 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
| +--------+ -------------| Client |----------------- | +--------+ | | | | | v | +-----------------+ | | Director | +---------------+ | |-----------------|<>----->| Builder | | | builder:Builder | |---------------| | |-----------------| |+ buildPart() | | | construct() | +---------------+ | | | ^ | +-----------------+ | | | | | v +----------------------+ | ConcreateBuilder | |----------------------| |+ buildPart() | |+ getResult():Product | +----------------------+ | | | +----v----+ | Product | +---------+
|
Java 简化版
案例, 创建一个有五个属性的 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 Computer { 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; } }
public class Computer { public void setCpu(String cpu) { this.cpu = cpu; } }
|
- 使用构造函数 - 弊端: 参数过多, 增加阅读, 调用复杂度
- 使用 new + set - 弊端: 不连续, 可能少设置属性什么的
Java 简化版方案:
- 在对象内部创建一个 public 的内部静态类 Builder
- 复制一份对象的属性到 Builder 中
- Builder 提供 set 方法
- 在对象内部添加一个私有的构造函数, 参数为 Builder
- 通过链式调用 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 39 40 41 42 43 44 45 46 47 48
| @Data public class Computer { private String cpu; private String ram; private int usbCount; private String keyboard; private String display;
private Computer(Builder builder) { this.cpu = builder.cpu; this.ram = builder.ram; this.usbCount = builder.usbCount; this.keyboard = builder.keyboard; this.display = builder.display; }
public static class Builder { private String cpu; private String ram; private int usbCount; private String keyboard; private String display;
public Builder(String cup, String ram) { this.cpu = cup; this.ram = ram; }
public Builder setUsbCount(int usbCount) { this.usbCount = usbCount; return this; }
public Builder setKeyboard(String keyboard) { this.keyboard = keyboard; return this; }
public Builder setDisplay(String display) { this.display = display; return this; }
public Computer build() { return new Computer(this); } } }
|
传统方式
涉及到的角色:
- Builder: 抽象接口, 定义了一系列需要实现的接口
- ConcreateBuilder: 具体的 Builder 实现类
- Production: 生成的产品
- Director: 具体 Builder 调用方法顺序的类
和上面的 Java 简化版相比, 传统模式只不过是把类内部的 Builder 实现独立出来了而已, 并没有什么其他很骚的操作. 不过相比于简单的版本, 它提供了 Builder 的扩展性, 在这个实现里, ConcreateBuilder 可以有多个版本的实现, 客户端可以根据实际需求调用所需要的 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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
| 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 + '\'' + '}'; } }
public interface ComputerBuilder { void setUsbCount();
void setKeyboard();
void setDisplay();
Computer getComputer(); }
public class MacBuilder implements ComputerBuilder { private Computer computer;
public MacBuilder(String cpu, String ram) { this.computer = new Computer(cpu, ram); }
@Override public void setUsbCount() { this.computer.setUsbCount(2); }
@Override public void setKeyboard() { this.computer.setKeyboard("Mac Keyboard"); }
@Override public void setDisplay() { this.computer.setDisplay("Mac Display"); }
@Override public Computer getComputer() { return this.computer; } }
public class LenovoBuilder implements ComputerBuilder { private Computer computer;
public LenovoBuilder(String cpu, String ram) { this.computer = new Computer(cpu, ram); }
@Override public void setUsbCount() { this.computer.setUsbCount(3); }
@Override public void setKeyboard() { this.computer.setKeyboard("Logic"); }
@Override public void setDisplay() { this.computer.setDisplay("ThinkVision"); }
@Override public Computer getComputer() { return this.computer; } }
public class ComputerDirector { public void makeComputer(ComputerBuilder builder) { builder.setDisplay(); builder.setKeyboard(); builder.setUsbCount(); } }
@Test public void test_builder() { ComputerDirector director = new ComputerDirector();
MacBuilder macBuilder = new MacBuilder("I5", "Sansong 4G"); director.makeComputer(macBuilder); System.out.println(macBuilder.getComputer());
LenovoBuilder lenovoBuilder = new LenovoBuilder("I7", "Kingston 8G"); director.makeComputer(lenovoBuilder); System.out.println(lenovoBuilder.getComputer()); }
|
建造者模式在 StringBuilder 中的应用
TODO
Effective Java item 2 摘录
参考文档