建造者模式——五种创建型模式之一

1.前言

单例模式可以创建出一个实例,并且这个实例存在的情况下,不会再创建出同样的实例。但是,有个明显的缺点,就是扩展性不高。实际开发中经常会遇到另外一种创建对象的情况,根据用户需求对实例进行设置。若放在构造函数中,要么加判断语句,要么重载构造函数,很不灵活;若通过setter注入,会增加许多与功能不相关的方法,而且对象的设置一般放在初始化时,不能让用户随时修改。

2.概念

建造者模式将一个复杂对象的构建与它的表示分离,使得对象专注于功能的展示,隐藏内部的实现。需要注意的是,一旦创建了对象,就不可修改配置了。还有最容易被误解的第二句,同样的构建过程可以创建不同的表示,即创建对象的算法应该独立于它的装配方式,允许创建结果有不同表示。

3.场景

食品厂准备生产月饼,需要根据市场喜好制作一套模具。然后,通过模具给月饼胚子成形,表面印上花纹。这里需要注意的是,我们可以新建不同的模具,让食品厂生产不同的月饼。

4.写法

public final class Mooncakes {
    
    // 1.创建的对象所具有的属性
    private int mSize;
    private String mName;
    
    private Mooncakes(int size, String name) {
        super();
        mSize = size;
        mName = name;
    }

    // 2.创建的对象所表现的功能
    public void product() {
        System.out.println("开始生产  " + mSize + "号大小  " + " " + mName + "花纹的月饼");
    }
    
    public static class Builder {

        // 3.构造器存储对象的属性
        private int mSize = 10;
        private String mName = "";
        
        // 4.向构造器设置对象的属性
        public Builder setSize(int size) {
            if (size > 0) {
                mSize = size;
            }
            return this;
        }
        
        public Builder setName(String name) {
            if (name != null && !name.equals("")) {
                mName = name;
            }
            return this;
        }
        
        // 5.通过构造器构造对象
        public Mooncakes build() {
            return new Mooncakes(mSize, mName);
        }
        
    }

}
public class Company {

    public static void main(String[] args) {
        // 先制作模具,在生产月饼
        new Mooncakes.Builder().setSize(4).setName("嫦娥").build().product();
        new Mooncakes.Builder().setName("嫦娥").build().product();
        new Mooncakes.Builder().setSize(4).build().product();
    }

}

不知道,大家可有发现一个问题。虽然一个具体的模具与一种月饼绑定,但是模具的制作没有规范,比较随意,不符合实际。所以,我们得关注第二点概念。这里有一些误区,大家可以参考happyhippy的文章,看最后的核心思想就够了,毕竟我们讨论的前提是算法不变。Director 定义了模具的制作规范,具体怎么实施由Builder实现类决定。

// 1.构造复杂对象默认实例
public class Mooncakes {
    
    private int mSize;
    private String mName;
    
    public Mooncakes() {
        super();
        mSize = 10;
        mName = "";
    }
    
    public void setmSize(int mSize) {
        this.mSize = mSize;
    }
    public void setmName(String mName) {
        this.mName = mName;
    }

    @Override
    public String toString() {
        return "Mooncakes [mSize=" + mSize + ", mName=" + mName + "]";
    }

}
// 2.导向器,定义复杂对象的构建算法
public class Director {
    
    private Builder mBuilder;
    
    public Director(Builder builder) {
        super();
        mBuilder = builder;
    }

    // 对于月饼而言,步骤是不会变的,先定型后印花
    public Mooncakes produceMooncakes() {
        return mBuilder.setSize(4).setName("嫦娥").build();
    }

}
// 3.抽象出对象的组装方式
public abstract class Builder {
    
    protected Mooncakes mCakes = new Mooncakes();
    
    public abstract Builder setSize(int size);
    
    public abstract Builder setName(String name);
    
    public Mooncakes build() {
        return mCakes;
    }

}
// 4.按照正常的方式设置
public class NormalBuilder extends Builder {

    @Override
    public Builder setSize(int size) {
        if (size > 0) {
            mCakes.setmSize(size);
        }
        return this;
    }

    @Override
    public Builder setName(String name) {
        if (name != null && !name.equals("")) {
            mCakes.setmName(name);
        }
        return this;
    }

}
// 5.按照我的方式设置
public class LanceBuilder extends Builder {

    @Override
    public Builder setSize(int size) {
        if (size > 0) {
            mCakes.setmSize(size * 2);
        }
        return this;
    }

    @Override
    public Builder setName(String name) {
        if (name != null && !name.equals("")) {
            mCakes.setmName("欢乐" + name);
        }
        return this;
    }

}
public class Company{

    public static void main(String[] args) {
        // 先制作模具,在生产月饼
        Mooncakes normalCakes = new Director(new NormalBuilder()).produceMooncakes();
        Mooncakes lanceCakes = new Director(new LanceBuilder()).produceMooncakes();
        System.out.println(normalCakes.toString());
        System.out.println(lanceCakes.toString());
    }

}

5.总结

建造者模式在安卓开发中较为常见,主要是调用系统的控件,比如说Dialog、Notification等需要做大量自定义设置的。由于通过链式调用,使得代码简洁易懂,将封装与扩展很好地结合起来。当然,缺点也很明显,多了不少类。

    原文作者:lanceJin
    原文地址: https://www.jianshu.com/p/91787da27e50
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞