生成器模式

Builder,也称为建造者模式;

允许分步创建复杂对象,

  • 在各种三方库中广泛应用,常常可以看到 XXX.Buider().setXxx().build() 这种,这些就是生成器模式;

  • StringBuilder 中的 append 也算是一种生成器模式;

  • Glide 的链式调用;

当一个类的构造函数参数数量超过4个,同时有些参数是可选的,那么就可以使用 生成器模式

优点:

  • 分步创建对象,暂缓创建步骤或递归运行创建步骤;

  • 生成不同参数的对象时,可以复用相同的代码;

  • 单一职责原则:将复杂构造代码从业务逻辑中抽离出来;

缺点:新增多个类,代码整体复杂程度有所增加。

实现

利用 静态内部类可以访问外部类的所有成员 这个特性,可以通过 静态内部类 来完成:

  1. 在需要应用生成器模式的类中声明一个静态内部类(通常叫做 Builder

  2. 内部类中维护一个外部类的实例,可以在构造方法中传递一些必要参数来初始化外部类的实例,同时可以给外部类设置默认值;

  3. 外部类的构造方法需要声明为 私有,强制使用静态内部类来实例化该外部类;

  4. 内部类编写一些方法用来设置外部类实例的参数,最后声明一个 build() 方法返回该外部类实例;

例子

假设有一个消息通知类,包括了标题、消息内容、收件人、通知时间、显示的回调、取消显示的回调等等;

其中某些值是可选的,比如显示回调和取消显示的回调,通知时间等等;

可以设置一些默认值;

class Message {

    interface MessageListener {
        void onShow();

        void onDismiss();
    }

    private MessageListener listener;

    private String title;

    private String content;

    private Long userId;

    private Long notifyTime;

    private Message() {
        this.listener = null;
        this.title = "";
        this.content = "";
        this.userId = -1L;
        this.notifyTime = -1L;
    }

    public void show() {
        if (listener != null) {
            listener.onShow();
        }
        System.out.printf("%s:\n %s\n", title, content);
    }

    public void dismiss() {
        if (listener != null) {
            listener.onDismiss();
        }
    }

    static class Builder {

        private final Message message;

        public Builder() {
            message = new Message();
        }

        public Message build() {
            return message;
        }

        public Builder setUser(long userId) {
            message.userId = userId;
            return this;
        }

        public Builder setTitle(String title) {
            message.title = title;
            return this;
        }

        public Builder setContent(String content) {
            message.content = content;
            return this;
        }

        public Builder setListener(MessageListener listener) {
            message.listener = listener;
            return this;
        }

        public Builder delayNotify(long delayMillions) {
            message.notifyTime = delayMillions;
            return this;
        }

        public static void main(String[] args) {
            Message.Builder builder = new Message.Builder();
            Message msg = builder
                    .setContent("This is content")
                    .setListener(
                            new Message.MessageListener() {
                                @Override
                                public void onShow() {
                                    System.out.println("showing");
                                }

                                @Override
                                public void onDismiss() {
                                    System.out.println("dismissed");
                                }
                            }
                    )
                    .setTitle("This is title string")
                    .build();

            msg.show();
            msg.dismiss();

        }
    }
}