为什么会有这个模式?
很多时候我们会构建非常复杂的类,内部初始化构成需要进行很多复杂交互操作,比如需要去数据库查询数据后作为属性初始值,或者说我们想控制它的内部初始化的过程,将构建过程分离出来。
1 简介
1.1 什么是建造者模式
建造者模式是创建模式之一,看到“建造”就明白这肯定是个不断累加的过程,比如说你想自己装一台笔记本,那你得装cpu、内存、硬盘、显卡、散热…需要很多东西来支持最后这个产品的完成,并且在组装过程中每一步要有一定的顺序,如果组装配件的品质不一样,最后得到的产品也会不一样。
简单来说就是通过一切些方式(继承、重载),动态创建具有多种属性的对象。
1.2 应用场景
上面介绍已经说过了,就是在构建复杂对象的时候,比如持有数据的对象,或者内部数据需要以一定顺序加载的时候。让构建的过程透明,使用者运行很少的代码就能创建一个十分复杂的对象。
2 原理
2.1 UML类图
2.2 模式分析
懂了吧。。。
- 产品经理和客户打交道明白具体需求,他也不需要明白具体实现,只要最后结果差不多就行
- 技术经理就在框架方法上进行把控,把任务分给下面的许多程序员
- 不同程序员负责产品不同部分的具体实现
- 不同的构建情况组合成不同的具体产品
3 具体实例
我们假设要生产一台“电脑”,请翻到计算机组成原理第一节,大声告诉我冯·诺依曼计算机由哪几部分组成?时隔几年还是忘不了大学时光呀
我们先看看咱们要做一个什么样的产品
public class Computer {
//运算器
private Calculator calculator;
//控制器
private Controller controller;
//存储器
private Storage storage;
//操作系统
private Os os;
//输入输出设备
private InputOutput io;
public Calculator getCalculator() {
return calculator;
}
public void setCalculator(Calculator calculator) {
this.calculator = calculator;
}
public Controller getController() {
return controller;
}
public void setController(Controller controller) {
this.controller = controller;
}
public Storage getStorage() {
return storage;
}
public void setStorage(Storage storage) {
this.storage = storage;
}
public Os getOs() {
return os;
}
public void setOs(Os os) {
this.os = os;
}
public InputOutput getIo() {
return io;
}
public void setIo(InputOutput io) {
this.io = io;
}
}
代码里Calculator、Controller …等类都是自己创建的,里面没什么方法,只是做标识,完整代码我已经上传了,下文里有链接
首先我们需要定义一个Builder,其实可以抽象类也可以接口,这个类定义了所有具体建造者应该做哪些事情
public abstract class AbstractBuilder {
//构建运算器
abstract void buildCalculator();
//构建控制器
abstract void buildController();
//构建输入输出设备
abstract void buildInputOutput();
//构建操作系统
abstract void buildOs();
//构造存储器
abstract void buildStorage();
//生产电脑
abstract Computer createComputer();
}
然后我们要创建具体的Builder来生产咱们的产品,这里为了举例我写了两个builder,一个用来生产联想电脑,一个用来生产mac
public class LenovoBuilder extends AbstractBuilder{
private Computer lenovoComputer = new Computer();
@Override
void buildCalculator() {
lenovoComputer.setCalculator(new LenovoCalculator());
}
@Override
void buildController() {
lenovoComputer.setController(new LenovoController());
}
@Override
void buildInputOutput() {
lenovoComputer.setIo(new LenovoIo());
}
@Override
void buildOs() {
lenovoComputer.setOs(new LenovoOs());
}
@Override
void buildStorage() {
lenovoComputer.setStorage(new LenovoStorage());
}
@Override
Computer createComputer() {
return lenovoComputer;
}
}
public class MacBuilder extends AbstractBuilder{
private Computer macComputer = new Computer();
@Override
void buildCalculator() {
macComputer.setCalculator(new MacCalculator());
}
@Override
void buildController() {
macComputer.setController(new MacController());
}
@Override
void buildInputOutput() {
macComputer.setIo(new MacIo());
}
@Override
void buildOs() {
macComputer.setOs(new MacOs());
}
@Override
void buildStorage() {
macComputer.setStorage(new MacStorage());
}
@Override
Computer createComputer() {
return macComputer;
}
}
可以看到上面两个具体builder类在实现抽象方法时调用了不同的组件来构建产品,即实际生产的是哪一种产品取决于是哪个具体builder在构建产品,我们还需要一个Director来和用户(client)沟通
public class Director {
private AbstractBuilder builder = null;
public Director(AbstractBuilder builder){
//指定当前实际builder
this.builder = builder;
}
public Computer createComputer(){
//组装电脑
builder.buildCalculator();
builder.buildController();
builder.buildInputOutput();
builder.buildOs();
builder.buildStorage();
//生产电脑
return builder.createComputer();
}
}
OK,现在顾客可以通过产品经理(Director)来或者指定产品了:
public class Client {
public static void main(String[] args) {
//先来一台联想的
Computer lenovoComputer = buyComputer(new LenovoBuilder());
//再来一台Mac
Computer macComputer = buyComputer(new MacBuilder());
}
private static Computer buyComputer(AbstractBuilder builder){
Director director = new Director(builder);
return director.createComputer();
}
}
点击获取完整代码
提取码: 5qce
除了上述用法之外,建造者模式还常用于优化构造函数参数过多,可读性不高的情况。优化前:
public class Computer {
private String calculator;
private String controller;
private String inputoutput;
private String os;
private String storage;
private Computer(){
}
Computer(String calculator,String controller,String inputoutput,String os,String storage){
this.calculator = calculator;
this.controller = controller;
this.inputoutput = inputoutput;
this.os = os;
this.storage = storage;
}
}
我们再来看看优化后:
public class ComputerPlus {
private String calculator;
private String controller;
private String inputoutput;
private String os;
private String storage;
private ComputerPlus(){
}
private ComputerPlus(Builder builder){
this.calculator = calculator;
this.controller = controller;
this.inputoutput = inputoutput;
this.os = os;
this.storage = storage;
}
public final static class Builder{
private String calculator;
private String controller;
private String inputoutput;
private String os;
private String storage;
public Builder(){
}
public Builder calculator(String calculator){
this.calculator = calculator;
return this;
}
public Builder controller(String controller){
this.controller = controller;
return this;
}
public Builder inputoutput(String inputoutput){
this.inputoutput = inputoutput;
return this;
}
public Builder os(String os){
this.os = os;
return this;
}
public Builder storage(String storage){
this.storage = storage;
return this;
}
public ComputerPlus createComputerPlus(){
return new ComputerPlus(this);
}
}
}
利用静态内部类来存储配置并组装目标对象,会让代码可读性提高不少,下面来看看使用时的差别:
public class Test {
public static void main(String[] args) {
//优化前
Computer computer = new Computer("1","2","3","4","5");
//优化后可读性大大提高
ComputerPlus computerPlus = new ComputerPlus.Builder()
.calculator("1")
.controller("2")
.inputoutput("3")
.os("4")
.storage("5")
.createComputerPlus();
}
}
是不是显得优雅多了 ?
当然建造者模式缺点也显而易见,和抽象工厂一样的代码膨胀问题,不过这也算是牺牲空间换取时间了吧。并且在拓展性上不如抽象工厂,要求创建的产品的相似性比较高的时候使用。
好的,对建造者模式的讲解就到这里了,如有错误欢迎指正!O(∩_∩)O