建造者模式

一、什么是建造者模式

Builder模式也叫建造者模式或者生成器模式,是由GoF提出的23种设计模式中的一种。

Builder模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建复合属性的对象。

二、代码演示

建造者模式用于创建复杂对象,关注于创建复杂对象的步骤过程。

在本例中,我们的目标是创建一个Product类的对象,创建对象本身是较为简单的,比如我们常用的工厂模式,可以翻阅之前的博客笔记,也就是new一下直接返回,因为工厂模式关注的是创建不同产品不同类型的对象,而不关注于其中某一个对象本身创建的过程。

建造者模式就是用来解决创建对象过程比较繁琐的对象,关注于创建对象的步骤、即为对象步骤化的装配组件。

目标:创建一个Product类的对象

package com.helius.service;

/**
 * @Author Helius
 * @Create 2019-09-25-21:37
 */
public class Product {
    private String buildA;
    private String buildB;
    private String buildC;
    private String buildD;

    public String getBuildA() {
        return buildA;
    }

    public void setBuildA(String buildA) {
        this.buildA = buildA;
    }

    public String getBuildB() {
        return buildB;
    }

    public void setBuildB(String buildB) {
        this.buildB = buildB;
    }

    public String getBuildC() {
        return buildC;
    }

    public void setBuildC(String buildC) {
        this.buildC = buildC;
    }

    public String getBuildD() {
        return buildD;
    }

    public void setBuildD(String buildD) {
        this.buildD = buildD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "buildA='" + buildA + '\'' +
                ", buildB='" + buildB + '\'' +
                ", buildC='" + buildC + '\'' +
                ", buildD='" + buildD + '\'' +
                '}';
    }
}

当然,为了演示,这个对象其实是比较简单的,但是在开发中,我们创建的对象可能是很复杂的,比如Mybatis的Configuration对象、SqlSessionFactory对象,都是通过建造者模式来完成创建。

这个Product对象有四个属性,想象一下这四个属性可能是很复杂的引用类型,我们要做的事情就是一步步的把这四个属性进行组装最后返回一个完整的Product对象。

我们分四个步骤来装配这个对象。

抽象的建造者

/**
 * @Author Helius
 * @Create 2019-09-25-21:36
 */
public abstract class Builder {
    abstract void buildA();
    abstract void buildB();
    abstract void buildC();
    abstract void buildD();

    abstract Product getProduct();
}

这里的方法名起的都很明显,我们这个抽象的建造者,就是用来装配这个Product对象的,

那思考一个问题,那为什么不直接在这样一个类中直接就进行装配,然后返回呢,而是抽象出这样一个类呢:前面已经说过,这个对象是很复杂的,他的对象每个部分可能是变化的,

比如我们去造一个房子,可能高楼和平房的建造步骤是一样的,都是先地基,再钢筋混凝土,再把电线铺进去,最后粉刷一下,就得到一个新房子啦。但是具体的过程却不相同。

小结

主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

接下来自然就是具体实现该步骤的具体的建造者类了

具体建造者

package com.helius.service;

/**
 * @Author Helius
 * @Create 2019-09-25-21:39
 */
public class ConcreteBuilder extends Builder {
     private Product product;

    public ConcreteBuilder() {
        product = new Product();
    }

    @Override
    void buildA() {
        // 这里也许还会有其他很多的操作
        product.setBuildA("地基");
    }

    @Override
    void buildB() {
        product.setBuildB("刚筋工程");
    }

    @Override
    void buildC() {
        product.setBuildC("铺电线");
    }

    @Override
    void buildD() {
        product.setBuildD("粉刷");
    }

    @Override
    Product getProduct() {
        return product;
    }
}

这个类ConcreteBuilder就 是具体的建造者了,当然也会有其他的建造者,有建高楼的建造者,有建平房的建造者。这里只举了一个,这里其实就可以体现了其扩展性了。
符合设计原则中的开闭原则

当然也是其缺点

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

思考一下:这个具体的建造者,具体用来做什么,我们在抽象的建造者中已经对Product对象的创建过程分成了四个步骤,这里就是具体的实现,这里我们做的事情,就是一步步的通过为Product对象的属性进行赋值。


再思考一个问题,进行到这一步,我们好像已经可以创建成一个对象了

就像这样

public class test2 {
    public static void main(String[] args) {
        ConcreteBuilder concreteBuilder = new ConcreteBuilder();
        concreteBuilder.buildA();
        concreteBuilder.buildB();
        concreteBuilder.buildC();
        concreteBuilder.buildD();
        Product product = concreteBuilder.getProduct();
        System.out.println(product);
    }
}

输出:

Product{buildA='地基', buildB='刚筋工程', buildC='铺电线', buildD='粉刷'}

如果这里建的是高楼,我们需要建一个平房,只需要再新建一个类似ConcreteBuilder的类就可以了。

貌似似这样,但是你看,这里把创建对象的过程完全暴露给了我们的使用者,有必要么?

假如步骤很多,或者更为复杂的创建步骤呢?

理解下面这句话

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

指挥者

public class Director {
    public Product create(Builder builder) {
        builder.buildA();
        builder.buildB();
        builder.buildC();
        builder.buildD();
        return builder.getProduct();
    }

}

按照上面的思绪,我们对创建过程进行封装一下,返回创建好的对象。


最终,我们写个测试类,测试一下

public class test {
    public static void main(String[] args) {

        Director director= new Director();
        Product product = director.create(new ConcreteBuilder());
        System.out.println(product.toString());
    }

}

输出的结果与上面自然是一致的。

总结

直接从其他地方copy了一段话过来,

建造者模式

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

介绍

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

何时使用:一些基本部件不会变,而其组合经常变化的时候。

如何解决:将变与不变分离开。

关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。

注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。


以上是我在学习建造者模式的一些自己的体会,可能理解的不一定正确。这个模式在开发中并不常用,在源码中时常见到。

posted @ 2019-09-25 22:30  HeliusKing  阅读(240)  评论(0编辑  收藏  举报