什么是建造者模式?

为什么会有这个模式?

很多时候我们会构建非常复杂的类,内部初始化构成需要进行很多复杂交互操作,比如需要去数据库查询数据后作为属性初始值,或者说我们想控制它的内部初始化的过程,将构建过程分离出来。

1 简介

1.1 什么是建造者模式

建造者模式是创建模式之一,看到“建造”就明白这肯定是个不断累加的过程,比如说你想自己装一台笔记本,那你得装cpu、内存、硬盘、显卡、散热…需要很多东西来支持最后这个产品的完成,并且在组装过程中每一步要有一定的顺序,如果组装配件的品质不一样,最后得到的产品也会不一样。
简单来说就是通过一切些方式(继承、重载),动态创建具有多种属性的对象。

1.2 应用场景

上面介绍已经说过了,就是在构建复杂对象的时候,比如持有数据的对象,或者内部数据需要以一定顺序加载的时候。让构建的过程透明,使用者运行很少的代码就能创建一个十分复杂的对象。

2 原理

2.1 UML类图

在这里插入图片描述

2.2 模式分析

懂了吧。。。

  • 产品经理和客户打交道明白具体需求,他也不需要明白具体实现,只要最后结果差不多就行
  • 技术经理就在框架方法上进行把控,把任务分给下面的许多程序员
  • 不同程序员负责产品不同部分的具体实现
  • 不同的构建情况组合成不同的具体产品

3 具体实例

我们假设要生产一台“电脑”,请翻到计算机组成原理第一节,大声告诉我冯·诺依曼计算机由哪几部分组成?时隔几年还是忘不了大学时光呀

我们先看看咱们要做一个什么样的产品

/**
 * what:    这是咱们的计算机 <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
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,其实可以抽象类也可以接口,这个类定义了所有具体建造者应该做哪些事情

/**
 * what:   建造者,咱们的技术经理<br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
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

/**
 * what:    咱们组装一台联想电脑. <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
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;
    }
}


/**
 * what:    咱们组装一台Mac. <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
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)沟通

/**
 * what:    产品经理开始忽悠客户了 <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
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)来或者指定产品了:

/**
 * what:    客户要买电脑了,肯定找咱们产品经理呀 <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
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

除了上述用法之外,建造者模式还常用于优化构造函数参数过多,可读性不高的情况。优化前:

/**
 * what:   多参数优化演示 <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
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;
    }
}

我们再来看看优化后:

/**
 * what:    优化后 <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
public class ComputerPlus {
    private String calculator;
    private String controller;
    private String inputoutput;
    private String os;
    private String storage;

    private ComputerPlus(){
    }

    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);
        }
    }
}

利用静态内部类来存储配置并组装目标对象,会让代码可读性提高不少,下面来看看使用时的差别:

/**
 * what:    优化测试. <br/>
 * how:     (如何使用). <br/>
 *
 * @author ycf created on 2020/7/13
 */
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

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值