美文网首页模型与算法
设计模式-建造者模式

设计模式-建造者模式

作者: NealLemon | 来源:发表于2019-08-04 14:32 被阅读8次

    简介

    定义

    将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

    相同的构建过程,可以创建不同的产品。比较试用于流程固定,但是顺序不固定的场景。

    特点

    用户只需指定需要建造的类型就可以得到他们,建造过程以及细节不需要知道。

    适用场景

    • 一个对象有复杂的内部结构
      • 属性
      • 步骤
    • 把复杂对象的创建和使用分离

    优点

    • 封装性好,创建和使用分离。
    • 扩展性好,建造类之间独立,一定程度上解耦。

    缺点

    • 产生多余的Builder对象
    • 修改内部结构,成本较大

    代码示例

    这里举一个日常的例子,比如我们日常去饭店吃饭。

    基本都会涉及到以下几个步骤:

    • 点餐
    • 选择堂食还是外带
    • 付款
    • 就餐
    • 打包

    当然以上几步骤不是固定的,因此我们使用建造者模式来实现,比较符合场景。

    首先我们需要一个吃货类

    在这个吃货类中,我们拥有以上的吃饭流程,这里有一个枚举类代表吃饭的形式。

    public class Eater {
    
        private String order;  //点餐
        private EatMode mode;  //堂食还是外带
        private String pay;    //付款
        private String eat;    //就餐
        private String pack;    //打包
    }
    
    /**
     * 就餐模式
     */
    public enum EatMode {
    
        HERE("堂食"),
        OUTSIDE("外带");
    
        private String label;
    
        EatMode(String label) {
            this.label = label;
        }
    
        public String getLabel() {
            return label;
        }
    }
    

    接着我们需要一个建造类

    我们将这个建造类以静态类的方式放在吃货类中。

    /**
     *  食客
     */
    public class Eater {
    
        private String order;  //点餐
        private EatMode mode;  //堂食还是外带
        private String pay;    //付款
        private String eat;    //就餐
        private String pack;    //打包
    
        public Eater(EaterBuilder eaterBuilder) {
            this.order = eaterBuilder.order;
            this.mode = eaterBuilder.mode;
            this.pack = eaterBuilder.pack;
            this.eat = eaterBuilder.eat;
            this.pay = eaterBuilder.pay;
        }
    
        @Override
        public String toString() {
            return "Eater{" +
                    "order='" + order + '\'' +
                    ", mode=" + mode.getLabel() +
                    ", pay='" + pay + '\'' +
                    ", eat='" + eat + '\'' +
                    ", pack='" + pack + '\'' +
                    '}';
        }
    
        public static class EaterBuilder {
            private String order;//点餐
            private EatMode mode; //堂食还是外带
            private String pay;        //付款
            private String eat;         //就餐
            private String pack;        //打包
    
            public EaterBuilder builderOrder(String order) {
                this.order = order;
                return this;
            }
    
            public EaterBuilder builerMode(EatMode eatMode) {
                this.mode = eatMode;
                return this;
            }
    
            public EaterBuilder builerPay(String pay) {
                this.pay = pay;
                return this;
            }
    
            public EaterBuilder builerEat(String eat) {
                this.eat = eat;
                return this;
            }
    
            public EaterBuilder builderPack(String pack) {
                this.pack = pack;
                return this;
            }
    
            public Eater build() {
                return new Eater(this);
            }
        }
    }
    

    在这个建造类中,我们建造了各种步骤,最后还包括了建造方法。 简单的建造者模式就完成了。接下来我们来看一下效果。

    就餐体验开始

    我们会选择在肯德基和正常饭店吃饭两种情景来演示,首先我们知道,

    一般我们去肯德基吃饭的步骤是

    1. 点餐
    2. 选择堂食还是带走
    3. 结账
    4. 吃吃吃

    而我们去饭店吃饭的步骤可能是

    1. 点餐
    2. 选择堂食
    3. 吃吃吃
    4. 结账
    5. 打包

    这两种正符合我们在一开始定义中的描述。我们简单的实现即可。

    public class EaterBootStrap {
    
        public static void main(String[] args) {
    
            //去肯德基吃饭
            Eater kfc = new Eater.EaterBuilder().
                    builderOrder("肯德基点餐").builerMode(EatMode.HERE).
                    builerPay("结账:100 RMB").builerEat("吃吃吃").build();
    
            System.out.println("肯德基就餐:" + kfc.toString());
            //去饭店吃饭
            Eater restaurant = new Eater.EaterBuilder().
                    builderOrder("饭店点餐").builerMode(EatMode.HERE).
                    builerEat("吃吃吃").builerPay("结账: 89 RMB").builderPack("打包剩菜").build();
    
            System.out.println("饭店就餐:" + restaurant.toString());
        }
    }
    

    框架源码举例

    JDK

    JDK中,我们在拼接字符串的时候,经常使用的就是StringBuilder 或者 StringBuffer。那么我们来看看内部的设计模式。

    我们来看一下StringBuffer中的 append()方法

    @Override
    public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }
    

    我们清晰的看到,这里也使用了和我们上面demo很类似的方式,就是建造者模式的主要体现。

    Spring

    在Spring中,我们也有建造者模式的实现。

    BeanDefinitionBuilder类中的实现:

    public static BeanDefinitionBuilder genericBeanDefinition(Class<?> beanClass) {
       BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
       builder.beanDefinition.setBeanClass(beanClass);
       return builder;
    }
    

    总结

    设计模式讲究的是一种平衡以及针对业务模型的匹配。不要滥用,徒增麻烦。

    相关文章

      网友评论

        本文标题:设计模式-建造者模式

        本文链接:https://www.haomeiwen.com/subject/cscydctx.html