生成器模式
Builder,也称为建造者模式;
允许分步创建复杂对象,
在各种三方库中广泛应用,常常可以看到
XXX.Buider().setXxx().build()这种,这些就是生成器模式;StringBuilder中的append也算是一种生成器模式;Glide的链式调用;
当一个类的构造函数参数数量超过4个,同时有些参数是可选的,那么就可以使用 生成器模式
优点:
分步创建对象,暂缓创建步骤或递归运行创建步骤;
生成不同参数的对象时,可以复用相同的代码;
单一职责原则:将复杂构造代码从业务逻辑中抽离出来;
缺点:新增多个类,代码整体复杂程度有所增加。
实现
利用 静态内部类可以访问外部类的所有成员 这个特性,可以通过 静态内部类 来完成:
在需要应用生成器模式的类中声明一个静态内部类(通常叫做
Builder)内部类中维护一个外部类的实例,可以在构造方法中传递一些必要参数来初始化外部类的实例,同时可以给外部类设置默认值;
外部类的构造方法需要声明为 私有,强制使用静态内部类来实例化该外部类;
内部类编写一些方法用来设置外部类实例的参数,最后声明一个
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();
}
}
}