设计模式(六)建造者模式

版权声明:转载必须注明本文转自晓_晨的博客:http://blog.csdn.net/niunai112

目录

导航

设计模式之六大设计原则
设计模式(一)单例模式
设计模式(二)工厂模式
设计模式(三)策略模式
设计模式(四)适配器模式
设计模式(五)享元模式
设计模式(六)建造者模式
设计模式(七)原型模式
设计模式(八)桥接模式
设计模式(九)外观模式
设计模式(十)组合模式
设计模式(十一)装饰器模式
设计模式(十二)代理模式
设计模式(十三)迭代器模式
设计模式(十四)观察者模式
设计模式(十五)中介者模式
设计模式(十六)命令模式
设计模式(十七)状态模式
设计模式(十八)访问者模式
设计模式(十九)责任链模式
设计模式(二十)解释器模式
设计模式(二十一)备忘录模式
设计模式(二十二)模板模式
设计模式总结篇(为什么要学习设计模式,学习设计模式的好处)

前言

在开发过程,有的时候会出现一个复杂对象的创建工作,这个对象一般组装模式固定,但是其中的参数会变,比如像电脑,汽车等,可拆分的东西,基本都能使用这个模式,只是看有没有必要,一些本来就是固定死的东西,用工厂模式或者享元模式会更好。

例子

假如你是一家云提供商,你的客户需要不同种类的产品,你要给不同客户提供产品。

/***
 *
 *@Author ChenjunWang
 *@Description:产品类,服务器有操作系统,所用语言,所选服务器和所选数据库
 *@Date: Created in 21:05 2018/3/20
 *@Modified By:
 *
 */

public class ServerProduct {
    String os;
    String language;
    String server;
    String database;

    public String getOs() {
        return os;
    }

    public void setOs(String os) {
        this.os = os;
    }

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    public String getServer() {
        return server;
    }

    public void setServer(String server) {
        this.server = server;
    }

    public String getDatabase() {
        return database;
    }

    public void setDatabase(String database) {
        this.database = database;
    }

    public String getEnvironment() {
        return "ServerProduct{" +
                "os='" + os + '\'' +
                ", language='" + language + '\'' +
                ", server='" + server + '\'' +
                ", database='" + database + '\'' +
                '}';
    }
}

假设有个客户选了经典套餐

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 21:19 2018/3/20
 *@Modified By:
 *
 */
public class Customer {
    public static void main(String[] args) {
        ServerProduct customer = new ServerProduct();
        customer.setOs("Ubuntu");
        customer.setLanguage("Java");;
        customer.setDatabase("Mysql");
        customer.setServer("Tomcat");
        System.out.println("客户1要的环境:" + customer.getEnvironment());
    }
}
运行结果如下
-------------------------------
客户1要的环境:ServerProduct{os='Ubuntu', language='Java', server='Tomcat', database='Mysql'}

没问题,环境出来了,客户很满意,后来又有一个客户说系统要centos,然后我们又要把全部流程走一遍

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 21:19 2018/3/20
 *@Modified By:
 *
 */
public class Customer {
    public static void main(String[] args) {
        ServerProduct customer = new ServerProduct();
        customer.setOs("Ubuntu");
        customer.setLanguage("Java");;
        customer.setDatabase("Mysql");
        customer.setServer("Tomcat");
        System.out.println("客户1要的环境:" + customer.getEnvironment());

        ServerProduct customer2 = new ServerProduct();
        customer2.setOs("Ubuntu");
        customer2.setLanguage("Java");;
        customer2.setDatabase("Mysql");
        customer2.setServer("Tomcat");
        System.out.println("客户2要的环境:" + customer2.getEnvironment());

    }
}
运行结果如下
-------------------------------
客户1要的环境:ServerProduct{os='Ubuntu', language='Java', server='Tomcat', database='Mysql'}
客户2要的环境:ServerProduct{os='CentOS', language='Java', server='Tomcat', database='Mysql'}

这样每次创建一个环境都需要写大量的重复代码,所以LZ

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 21:12 2018/3/20
 *@Modified By:
 *
 */
public interface Builder {
    Builder installOS(String OS);
    Builder installLanguage(String language);
    Builder installServer(String server);
    Builder installDatabase(String database);
    ServerProduct getProduct();
}

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 22:04 2018/3/20
 *@Modified By:
 *
 */
public class Classic implements Builder{

    private ServerProduct serverProduct = new ServerProduct();
    @Override
    public Builder installOS(String OS) {
        serverProduct.os = OS;
        return this;
    }


    @Override
    public Builder installLanguage(String language) {
        serverProduct.language = language;
        return this;
    }

    @Override
    public Builder installServer(String server) {
        serverProduct.server = server;
        return this;
    }

    @Override
    public Builder installDatabase(String database) {
        serverProduct.database = database;
        return this;
    }

    @Override
    public ServerProduct getProduct() {
        return serverProduct;
    }
}

/***
 *
 *@Author ChenjunWang
 *@Description:
 *@Date: Created in 22:11 2018/3/20
 *@Modified By:
 *
 */
public class Director {
    private Builder builder = new Classic();
    public ServerProduct createClassicUbuntuEnvironment(){
        builder.installOS("Ubuntu").installLanguage("Java").installServer("Tomcat").installDatabase("Mysql");
        return builder.getProduct();
    }
    public ServerProduct createClassicCentOSEnvironment(){
        builder.installOS("CentOS").installLanguage("Java").installServer("Tomcat").installDatabase("Mysql");
        return builder.getProduct();
    }
}


public class Customer {
    public static void main(String[] args) {
        Director director = new Director();
        ServerProduct classicCentOSEnvironment1 = director.createClassicCentOSEnvironment();
        System.out.println("创建第一个环境:" + classicCentOSEnvironment1.getEnvironment());
        ServerProduct classicCentOSEnvironment2 = director.createClassicUbuntuEnvironment();
        System.out.println("创建第二个环境:" + classicCentOSEnvironment2.getEnvironment());



    }
}
运行结果如下
--------------------------
创建第一个环境:ServerProduct{os='CentOS', language='Java', server='Tomcat', database='Mysql'}
创建第二个环境:ServerProduct{os='Ubuntu', language='Java', server='Tomcat', database='Mysql'}

UML图
builder
其实,建造者模式到这就结束了,但是LZ还是要拓展一下,这里存在一个大问题,就是假如使用上面的方法的话,director 再次调用create方法的话,之前的信息就会被替换掉,因为他们引用的是同一个对象。所以Main应该要按下面这样写才对。

public class Customer {
    public static void main(String[] args) {
        Director director = new Director();
        ServerProduct classicCentOSEnvironment1 = director.createClassicCentOSEnvironment();
        System.out.println("创建第一个环境:" + classicCentOSEnvironment1.getEnvironment());
        director = new Director();
        classicCentOSEnvironment2 = director.createClassicUbuntuEnvironment();
        System.out.println("创建第二个环境:" + classicCentOSEnvironment2.getEnvironment());
        System.out.println("创建第一个环境:" + classicCentOSEnvironment1.getEnvironment());

    }
}

---------------------------------------------------
创建第一个环境:ServerProduct{os='CentOS', language='Java', server='Tomcat', database='Mysql'}
创建第二个环境:ServerProduct{os='Ubuntu', language='Java', server='Tomcat', database='Mysql'}
创建第一个环境:ServerProduct{os='CentOS', language='Java', server='Tomcat', database='Mysql'}

这样就没有什么问题了。每次新建出来的环境都是不同的对象。

总结

优点

建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。

每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合“开闭原则”。

可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰。

缺点

建造者模式所创建的产品具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,不适合使用建造者模式,因此其使用范围受到一定的限制。

如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本。

Git地址

本篇实例Github地址:https://github.com/stackisok/Design-Pattern/tree/master/src/builder

回到最上方


有什么不懂或者不对的地方,欢迎留言。
喜欢LZ文章的小伙伴们,可以关注一波,也可以留言,LZ会回你们的。
觉得写得不错的小伙伴,欢迎转载,但请附上原文地址,谢谢^_^!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章