前言
建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
1、建造者模式特征
1.1 建造者模式UML图
1.2 建造者模式角色
在这样的设计模式中,有以下几个角色:
- builder:为创建一个产品对象的各个部件指定抽象接口。
- ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并 提供一个检索产品的接口。
- Director:构造一个使用Builder接口的对象。
- Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
1.3 建造者模式使用场景
- 创建复杂对象的算法独立于组成对象的部件
- 同一个创建过程需要有不同的内部表象的产品对象
2、建造者模式代码实现
2.1 标准写法
builder:
/**
* 抽象建造者
* Created by Administrator on 2018/1/24.
*/
public interface Builder {
public void makeWindow();
public void makeFloor();
public Room build();
}
ConcreteBuilder:
/**
* Created by Administrator on 2018/1/24.
* 持有对房子的引用
*/
public class WorkBuilder implements Builder {
Room room = new Room();
@Override
public void makeWindow() {
room.setWindow("欧式窗户");
}
@Override
public void makeFloor() {
room.setFloor("日式地板");
}
@Override
public Room build() {
return room;
}
}
Director:
/**
* Created by Administrator on 2018/1/24.
* 设计者(指导者)
*
* 他知道 房屋怎么设计
* 他肯定对 工人所具备的能力有所理解
*/
public class Designer {
public Room build(Builder builder){
builder.makeFloor();
builder.makeWindow();
return builder.build();
}
}
Product:
/**
* Created by Administrator on 2018/1/24.
*/
public class Room {
private String window;
private String floor;
public String getWindow() {
return window;
}
public void setWindow(String window) {
this.window = window;
}
public String getFloor() {
return floor;
}
public void setFloor(String floor) {
this.floor = floor;
}
@Override
public String toString() {
return "Room{" +
"window='" + window + '\'' +
", floor='" + floor + '\'' +
'}';
}
}
Client调用:
public class Client {
public static void main(String[] args) {
Builder build = new WorkBuilder();
Designer designer = new Designer();
Room room = designer.build(build);
System.out.println(room.toString());
//房间暴露了构建过程不合理
room.setFloor("XXXXX");
room.setWindow("XXXXX");
}
}
运行结果:
Room{window='欧式窗户', floor='日式地板'}
注意:Product本身暴露了产品构建过程不合理
2.2 变种优化写法
Product:
public class Room {
private String window;
private String floor;
private String lamp;
public Room apply(WorkBuilder.RoomParams params){
window = params.window;
floor = params.floor;
lamp = params.floor;
return this;
}
@Override
public String toString() {
return "Room{" +
"window='" + window + '\'' +
", floor='" + floor + '\'' +
", lamp='" + lamp + '\'' +
'}';
}
}
ConcreteBuilder:
含有和Product同样参数的内部类RoomParams
public class WorkBuilder {
Room room = new Room();
private RoomParams params = new RoomParams();
public WorkBuilder makeWindow(String window){
params.window = window;
return this;
}
public WorkBuilder makeFloor(String floor){
params.floor = floor;
return this;
}
public WorkBuilder makeLamp(String lamp){
params.lamp = lamp;
return this;
}
/**
* 隐藏构建过程
*真正的构建者
* */
public Room build(){
room.apply(params);
return room;
}
public class RoomParams{
public String window;
public String floor;
public String lamp;
}
}
Client调用:
public class Client {
public static void main(String[] args){
//隐藏了构建过程合理
Room room = new WorkBuilder()
.makeFloor("日式地板")
.makeWindow("欧式窗户")
.makeLamp("中式吊灯")
.build() ;
System.out.println(room.toString());
}
}
运行结果:
Room{window='欧式窗户', floor='日式地板', lamp='日式地板'}
Product类隐藏构建过程,设计合理
3、Android源码中使用
建造者典型例子是AlertDialog,它的基本写法是:
public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert;
protected AlertDialog(Context context) {
this(context, resolveDialogTheme(context, 0), true);
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mAlert.setTitle(title);
}
public void setMessage(CharSequence message) {
mAlert.setMessage(message);
}
public static class Builder {
private final AlertController.AlertParams P;
private int mTheme;
public Builder(Context context, int theme) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, theme)));
mTheme = theme;
}
public Builder setTitle(int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
public Builder setMessage(CharSequence message) {
P.mMessage = message;
return this;
}
public Builder setOnCancelListener(OnCancelListener onCancelListener) {
P.mOnCancelListener = onCancelListener;
return this;
}
public AlertDialog create() {
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
...
return dialog;
}
public AlertDialog show() {
AlertDialog dialog = create();
dialog.show();
return dialog;
}
}
}