• 设计模式——建造者模式


    前面讲述了工厂模式,主要用于创建对象;建造者模式与工厂模式的相同之处在于都属于创建型的设计模式,即都是为解决方便创建对象而产生的设计模式!

    不同之处在于,工厂模式一般用于创建产品本身较为简单,但是产品种类比较多,产品分类较复杂的场景;建造者模式一般用于创建产品本身比较复杂,但是不同产品的创建都需要遵循一定的流程章法,并且产品在组成上不存在很大的相似性,而展现有较大差异。

    建造者模式的思想

    产品 - 可以是抽象类,也可以是普通类

    抽象建造者 - 约束建造所需流程。抽象类

    实际建造者(继承与抽象建造者)  - 实际生产产品的类

    导演类 - 用于操作实际建造者,生产产品;

    下面看经典的代码:

    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    /**
     * @description 抽象的建造者
     *              可以约束真实建造者可能需要执行的流程,一定程度上保证某些流程不被遗漏
     *              也可以只有一个produce方法,具体实现交由子类,但这样在一定程度上就放松了约束
     * @author panteng
     * @date 17-2-4.
     */
    public abstract class AbstractBuilder {
        public abstract void producePart1();
        public abstract void producePart2();
        public abstract void producePart3();
    
        /**
         *
         * @return Product可以是具体的类,也可以是抽象类
         */
        public abstract Product getProduct();
    }
    AbstractBuilder
    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    /**
     * @description 导演类
     *              导演类和产品没有直接关系,和建造者有直接关系,只按照一定的规则操作建造者生产产品
     * @author panteng
     * @date 17-2-4.
     */
    public class Director {
        private AbstractBuilder builder;
    
        public Director(){
        }
    
        public Director(AbstractBuilder inBuilder){
            this.builder = inBuilder;
        }
    
        /**
         * @description 在此保证建造者必须执行那些流程
         * @return
         */
        public Product buildProduct(){
            builder.producePart1();
            builder.producePart2();
            builder.producePart3();
            return builder.getProduct();
        }
    
        public AbstractBuilder getBuilder(){
            return builder;
        }
        public void setBuilder(AbstractBuilder builder){
            this.builder = builder;
        }
    }
    Director
    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    /**
     * @description 产品对象
     *              可以是抽象类
     * @author panteng
     * @date 17-2-4.
     */
    public class Product {
        public String part1;
        public String part2;
        public String part3;
    
        public String getPart1(){
            return part1;
        }
        public void setPart1(String part1){
            this.part1 = part1;
        }
        public String getPart3(){
            return part3;
        }
        public void setPart3(String part3){
            this.part3 = part3;
        }
        public String getPart2(){
            return part2;
        }
        public void setPart2(String part2){
            this.part2 = part2;
        }
    
        /**
         * Returns a string representation of the object. In general, the
         * {@code toString} method returns a string that
         * "textually represents" this object. The result should
         * be a concise but informative representation that is easy for a
         * person to read.
         * It is recommended that all subclasses override this method.
         * <p>
         * The {@code toString} method for class {@code Object}
         * returns a string consisting of the name of the class of which the
         * object is an instance, the at-sign character `{@code @}', and
         * the unsigned hexadecimal representation of the hash code of the
         * object. In other words, this method returns a string equal to the
         * value of:
         * <blockquote>
         * <pre>
         * getClass().getName() + '@' + Integer.toHexString(hashCode())
         * </pre></blockquote>
         *
         * @return a string representation of the object.
         */
        @Override
        public String toString(){
            return this.part1 + " - " + this.part2 + " - " + this.part3;
        }
    }
    Product
    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    /**
     * @description 实际建造者
     * @author panteng
     * @date 17-2-4.
     */
    public class RealBuilder extends AbstractBuilder {
        private Product product = new Product();
        @Override
        public void producePart1(){
            product.setPart1("p1");
        }
        @Override
        public void producePart2(){
            product.setPart2("p2");
        }
        @Override
        public void producePart3(){
            product.setPart3("p3");
        }
    
        /**
         *
         * @return Product可以是具体的类,也可以是抽象类
         */
        @Override
        public Product getProduct(){
            return product;
        }
    }
    RealBuilder
    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    /**
     * @description 实际建造者
     * @author panteng
     * @date 17-2-4.
     */
    public class RealBuilder2 extends AbstractBuilder {
        private Product product = new Product();
        @Override
        public void producePart1(){
            product.setPart1("p2:1");
        }
        @Override
        public void producePart2(){
            product.setPart2("p2:2");
        }
        @Override
        public void producePart3(){
            product.setPart3("p2:3");
        }
    
        /**
         *
         * @return Product可以是具体的类,也可以是抽象类
         */
        @Override
        public Product getProduct(){
            return product;
        }
    }
    RealBuilder2
    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    import org.junit.Test;
    
    /**
     * @description 测试建造者模式
     * @author panteng
     * @date 17-2-4.
     */
    public class BuilderModelTest {
        @Test
        public void builderModelTest(){
            RealBuilder builder = new RealBuilder();
            Director director = new Director(builder);
            Product product = director.buildProduct();
            System.out.println(product);
    
            RealBuilder2 builder2 = new RealBuilder2();
            director.setBuilder(builder2);
            product = director.buildProduct();
            System.out.println(product);
    
        }
    }
    BuilderModelTest

    个人认为,以上设计模式有一个不足之处,即一个builder只能生产一个产品;

    解决此不足之处的方案:在AbstractBuilder中增加一个设置product的方法,在director的 buildProduct方法中,new一个新的product,然后注入。这样做的缺点是在破坏了导演类与创建产品无关的约定。实践是检验真理的标准,如果这种方案能很好的解决经典模式的不足,更好的在实践中应用,也未尝不可。欢迎各位吐槽

    修改后代码如下:

    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    /**
     * @description 抽象的建造者
     *              可以约束真实建造者可能需要执行的流程,一定程度上保证某些流程不被遗漏
     *              也可以只有一个produce方法,具体实现交由子类,但这样在一定程度上就放松了约束
     * @author panteng
     * @date 17-2-4.
     */
    public abstract class AbstractBuilder {
        Product product = new Product();
    
        public abstract void producePart1();
        public abstract void producePart2();
        public abstract void producePart3();
    
        /**
         *
         * @return Product可以是具体的类,也可以是抽象类
         */
        public abstract Product getProduct();
    
        public void setProduct(Product product){
            this.product = product;
        }
    }
    AbstractBuilder
    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    /**
     * @description 实际建造者
     * @author panteng
     * @date 17-2-4.
     */
    public class RealBuilder extends AbstractBuilder {
    
        @Override
        public void producePart1(){
            product.setPart1("p1");
        }
        @Override
        public void producePart2(){
            product.setPart2("p2");
        }
        @Override
        public void producePart3(){
            product.setPart3("p3");
        }
    
        /**
         *
         * @return Product可以是具体的类,也可以是抽象类
         */
        @Override
        public Product getProduct(){
            return product;
        }
    }
    RealBuilder
    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    /**
     * @description 实际建造者
     * @author panteng
     * @date 17-2-4.
     */
    public class RealBuilder2 extends AbstractBuilder {
        private Product product = new Product();
        @Override
        public void producePart1(){
            product.setPart1("p2:1");
        }
        @Override
        public void producePart2(){
            product.setPart2("p2:2");
        }
        @Override
        public void producePart3(){
            product.setPart3("p2:3");
        }
    
        /**
         *
         * @return Product可以是具体的类,也可以是抽象类
         */
        @Override
        public Product getProduct(){
            return product;
        }
    }
    RealBuilder2
    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    /**
     * @description 导演类
     *              导演类和产品没有直接关系,和建造者有直接关系,只按照一定的规则操作建造者生产产品
     * @author panteng
     * @date 17-2-4.
     */
    public class Director {
        private AbstractBuilder builder;
    
        public Director(){
        }
    
        public Director(AbstractBuilder inBuilder){
            this.builder = inBuilder;
        }
    
        /**
         * @description 在此保证建造者必须执行那些流程
         * @return
         */
        public Product buildProduct(){
            builder.setProduct(new Product());
            builder.producePart1();
            builder.producePart2();
            builder.producePart3();
            return builder.getProduct();
        }
    
        public AbstractBuilder getBuilder(){
            return builder;
        }
        public void setBuilder(AbstractBuilder builder){
            this.builder = builder;
        }
    }
    Director
    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    /**
     * @description 产品对象
     *              可以是抽象类
     * @author panteng
     * @date 17-2-4.
     */
    public class Product {
        public String part1;
        public String part2;
        public String part3;
    
        public String getPart1(){
            return part1;
        }
        public void setPart1(String part1){
            this.part1 = part1;
        }
        public String getPart3(){
            return part3;
        }
        public void setPart3(String part3){
            this.part3 = part3;
        }
        public String getPart2(){
            return part2;
        }
        public void setPart2(String part2){
            this.part2 = part2;
        }
    
        /**
         * Returns a string representation of the object. In general, the
         * {@code toString} method returns a string that
         * "textually represents" this object. The result should
         * be a concise but informative representation that is easy for a
         * person to read.
         * It is recommended that all subclasses override this method.
         * <p>
         * The {@code toString} method for class {@code Object}
         * returns a string consisting of the name of the class of which the
         * object is an instance, the at-sign character `{@code @}', and
         * the unsigned hexadecimal representation of the hash code of the
         * object. In other words, this method returns a string equal to the
         * value of:
         * <blockquote>
         * <pre>
         * getClass().getName() + '@' + Integer.toHexString(hashCode())
         * </pre></blockquote>
         *
         * @return a string representation of the object.
         */
        @Override
        public String toString(){
            return super.toString() + " = " + this.part1 + " - " + this.part2 + " - " + this.part3;
        }
    }
    Product
    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.builder;
    
    import org.junit.Test;
    
    /**
     * @description 测试建造者模式
     * @author panteng
     * @date 17-2-4.
     */
    public class BuilderModelTest {
        @Test
        public void builderModelTest(){
            RealBuilder builder = new RealBuilder();
            Director director = new Director(builder);
            Product product = director.buildProduct();
            System.out.println(product);
            product = director.buildProduct();
            System.out.println(product);
    
            RealBuilder2 builder2 = new RealBuilder2();
            director.setBuilder(builder2);
            product = director.buildProduct();
            System.out.println(product);
    
        }
    }
    BuilderModelTest

    建造者模式一般在游戏中使用较多:如不同类型的角色,一般属性相同,展现不同; 不同场景的创建,都要创建天、地、物、人等!

    ===========================设计模式系列文章=========================

    简单工厂模式

    工厂方法模式

    抽象工厂模式

    建造者模式

    原型模式

    适配器模式

    桥接模式

    装饰模式

    代理模式

    组合模式

    门面模式

    享元模式

    责任链模式

    命令模式

    中介者模式

    备忘录模式

    观察者模式

    状态模式

    策略模式

    模板方法模式

    访问者模式

  • 相关阅读:
    「Poetize7」Freda的访客
    「Poetize8」Divisible
    「Poetize5」Vani和Cl2捉迷藏
    1082. 员工的重要度
    1080. 最大的岛
    1079. 连续子串计数(经典)
    1078. 数组的度
    1071. 词典中最长的单词
    1068. 寻找数组的中心索引
    1062. 洪水填充(经典)
  • 原文地址:https://www.cnblogs.com/tengpan-cn/p/6366073.html
Copyright © 2020-2023  润新知