建造者模式
建造者模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
结构图
代码实现
抽象构造类Builder:定义Product生产的过程,不添加细节。并提供返回Product的方法
/**
* 抽象构造类
* @author xukai
* 2016年3月15日 下午10:55:02
*/
public abstract class Builder {
public abstract void builderPartA();
public abstract void builderPartB();
public abstract Product getResult();
}
具体构造类1:构造产品部件
/**
* 具体构造者类1
* @author xukai
* 2016年3月15日 下午10:57:37
*/
public class ConcreteBuilder1 extends Builder {
private Product product = new Product();
@Override
public void builderPartA() {
product.add("部件A");
}
@Override
public void builderPartB() {
product.add("部件B");
}
@Override
public Product getResult() {
return product;
}
}
具体构造类2:
/**
* 具体构造者类1
* @author xukai
* 2016年3月15日 下午10:57:37
*/
public class ConcreteBuilder2 extends Builder {
private Product product = new Product();
@Override
public void builderPartA() {
product.add("部件X");
}
@Override
public void builderPartB() {
product.add("部件Y");
}
@Override
public Product getResult() {
return product;
}
}
具体构建的Product(可以为抽象类)
import java.util.ArrayList;
import java.util.List;
/**
* 具体产品类
* @author xukai
* 2016年3月15日 下午10:50:55
*/
public class Product {
List<String> parts = new ArrayList<>();
public void add(String part){
parts.add(part);
}
public void show(){
for(String part : parts){
System.out.println(part);
}
}
}
指挥者类:决定组装什么样子的Product
/**
* 指挥者类
* @author xukai
* 2016年3月15日 下午10:58:39
*/
public class Director {
public void construct(Builder builder){
builder.builderPartA();
builder.builderPartB();
}
}
客户端测试:
public class Client {
public static void main(String[] args) {
Director director = new Director();
Builder b1 = new ConcreteBuilder1();
Builder b2 = new ConcreteBuilder2();
director.construct(b1);
Product p1 = b1.getResult();
p1.show();
director.construct(b2);
Product p2 = b2.getResult();
p2.show();
}
}
控制台:
部件A
部件B
部件X
部件Y
产品类Product:一个复杂的对象,换句话说该对象在创建的过程中比较复杂。可以是一个具体类,也可以是一个抽象类与它不同的实现组成。
抽象建造者Builder:将建造Product的具体过程交给它的子类实现。容易扩展,至少包括两个方法,一个建造Product,一个返回建造的Product。
具体建造者ConcreteBuilder:继承抽象建造者类,实现父类未实现的方法:组建产品,返回组建好的产品。
指挥者Director:负责调用适当的具体建造者来组建产品,它直接与建造者交互。用来封装易变的部分。
demo
问题:组装一台电脑,包括鼠标、键盘、显示屏和主机等。结构图
代码实现
具体产品Computer:/**
* 计算机
*
* @author xukai 2016年3月16日 下午8:49:00
*/
public class Computer {
private String keyboard;
private String mouse;
private String display;
private String host;
//getter setter
@Override
public String toString() {
return "Computer [keyboard=" + keyboard + ", mouse=" + mouse + ", display=" + display + ", host=" + host + "]";
}
}
抽象构造类:
/**
* 计算机抽象建造类
* @author xukai
* 2016年3月16日 下午9:06:07
*/
public abstract class ComputerBuilder {
protected Computer computer = new Computer();
public abstract void setKeyboard();
public abstract void setMouse();
public abstract void setDisplay();
public abstract void setHost();
public Computer returnComputer(){
return computer;
}
}
具体构造类1:
/**
* 计算机具体建造类
* @author xukai
* 2016年3月16日 下午9:06:16
*/
public class ConcreteBuilder1 extends ComputerBuilder {
@Override
public void setKeyboard() {
super.computer.setKeyboard("罗技键盘");
}
@Override
public void setMouse() {
super.computer.setMouse("罗技鼠标");
}
@Override
public void setDisplay() {
super.computer.setDisplay("DELL显示屏");
}
@Override
public void setHost() {
super.computer.setHost("Inter主机");
}
}
具体构造类2:
/**
* 计算机具体建造类
* @author xukai
* 2016年3月16日 下午9:06:29
*/
public class ConcreteBuilder2 extends ComputerBuilder {
@Override
public void setKeyboard() {
super.computer.setKeyboard("Google键盘");
}
@Override
public void setMouse() {
super.computer.setMouse("Google鼠标");
}
@Override
public void setDisplay() {
super.computer.setDisplay("索尼显示屏");
}
@Override
public void setHost() {
super.computer.setHost("苹果主机");
}
}
导演类:
/**
* 导演类:决定创建具体的Computer
* @author xukai
* 2016年3月16日 下午9:06:33
*/
public class Director {
ComputerBuilder builder;
public void installComputer(ComputerBuilder builder){
this.builder = builder;
builder.setKeyboard();
builder.setMouse();
builder.setDisplay();
builder.setHost();
}
}
客户端测试:
public class CilentTest {
public static void main(String[] args) {
ComputerBuilder builder = new ConcreteBuilder1();
Director director = new Director();
director.installComputer(builder);
System.out.println(director.builder.returnComputer());
builder = new ConcreteBuilder2();
director.installComputer(builder);
System.out.println(director.builder.returnComputer());
}
}
控制台输出:
Computer [keyboard=罗技键盘, mouse=罗技鼠标, display=DELL显示屏, host=Inter主机]
Computer [keyboard=Google键盘, mouse=Google鼠标, display=索尼显示屏, host=苹果主机]
创建了不同的电脑组装。
总结
使用建造者模式,用户只需要指定需要建造的类型就可以得到具体产品,具体建造的过程和细节不需要知道。
建造者模式的封装性很好。产品类和抽象建造者类比较稳定,主要的业务逻辑封装在Director中。另外很容易进行扩展,有新的需求,可以通过实现新的构造者来完成。
建造者和工厂模式的区别
显而易见,建造者模式和工厂模式非常相似,在设计上,建造者模式比工厂模式多了一个指挥类或者说是导演类。当然,如果把这个Director看做客户端,那么就是一个工厂模式了。还有就是,与工厂模式相比,建造者模式用来创建更加复杂的对象,对象的创建过程更为复杂。
工厂模式中,对象的创建全部过程封装在工厂类中,由工厂类向客户端提供产品。
建造者模式中,建造者一般只提供产品类中各个组件的建造,而将具体建造过程交给导演类。导演类负责将各个组件按照特定规则组建产品,然后交付给客户端。
一般来说,如果产品建造很复杂,那么用工厂模式;如果产品的建造更复杂,那么用建造者模式。