定义
建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。
使用场景
- 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员变量。
- 需要生成的产品对象的属性相互依赖,需要制定其生成顺序。
- 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入指挥者类,将创建过程封装在指挥者类,而不在建造者类和客户类。
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
建造者模式概述
结构图
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| public class Computer{ protected String mBoard; protected String mDisplay; protected String mOS; public String getBoard(){ return mBoard; } public String setBoard(String board){ mBoard = board; } public String getDisplay(){ return mDisplay; } public String setDisplay(String display){ mDisplay = display; } public String getOS(){ return mOS; } public String setOS(String OS){ mOS = OS; } }
public abstract class ComputerBuilder{ private Computer computer = new Computer(); public abstract void buildBoard(); public abstract void buildDisplay(); public abstract void buildOS(); public Computer create(){ return computer; } }
public class MacbookBuilder extends ComputerBuilder{ @Override public void buildBoard(){ computer.setBoard("Intel"); } @Override public void buildDisplay(){ computer.setDisplay("Retina"); } @Override public void buildOS(){ computer.setOS("OS X 10.13"); } }
public class Director{ public Computer construct(ComputerBuilder computerbuilder){ Computer computer; computerbuilder.buildBoard(); computerbuilder.buildDisplay(); computerbuilder.buildOS(); computer = computerbuilder.create(); return computer; } }
public class Client{ public static void main(String[] args){ Direcotr director = new Director(); ComputerBuilder builder = new MacbookBuilder(); Computer computer; computer = diretor.construct(builder); System.out.println(computer.mBoard); System.out.println(computer.mDisplay); System.out.println(computer.mOS); } }
|
省略Director
在Android源码中,最常用到的Builder模式就是AlertDialog.Builder
,使用该Builder来构建复杂的AlertDialog对象。从类名就可以看出这就是Builder模式,通过Builder对象组装Dialog的各个部分,如title、buttons、Message等,将Dialog的构造和表示分离,这里作简单分析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| public class AlertDialog extends Dialog implements DialogInterface{ private AlertController mAlert; protected AlertDialog(Context context, int theme){ this(context, theme, true); } AlertDialog(Context context, int theme, boolean createContextWrapper){ super(context, resolveDialogTheme(context, theme), createContextWrapper); mWindow.alwaysReadCloseOnTouchAttr(); mAlert = new AlertControllor(getContext(), this, getWindow()); } @Override public void setTitle(CharSequence title){ super.setTitle(title); mAlert.setTitle(title); } public void setCustomTitle(View customTitleView){ mAlert.setTitle(customTitleView); }
public void setMessage(CharSequence message){ mAlert.setMessage(message); } public static class Builder{ private final AlertController.AlertParams P; public Builder(Context context){ this(context, resolveDialogTheme(context, 0)); } public Builder(Context context, imt theme){ P = new AlertController.AlertParams(new ContextThemeWrapper( context, resolveDilalogTheme(context, theme))); mTheme = theme; } public Builder setTitle(CharSequence title){ P.mTitle = title; return this; } public Builder setMessage(CharSequence message){ P.message = message; return this; } public Builder setView(View view){ P.mView = view; P.mViewSpacingSecified = false; return this; } public AlertDilaog create(){ final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false); P.apply(dialog.mAlert); dialog.setCancelable(P.mCancelable); if(P.mCanelable){ dialog.setCanceledOnTouchOutside(true); } dialog.setOnCancelListener(P.mOnCancelListener); if(P.mOnKeyListener != null){ dialog.setOnKeyListener(P.mOnKeyListener); } return dialog; }
|
上述代码中,Builder类可以设置AlertDialog中的title,message,button等参数,这些参数存储在类型为AlertController.AlertParams的成员变量P中,AlertController.AlertParams中包含了AlertDialog中的成员变量。调用Builder类的create()函数时会创建AlertDialog,并将Builder成员变量P保存的参数应用到AlertDialog的mAlert对象中,即apply()
函数,接下来的apply()
,show()
,setupView()
不再展开分析。
在AlertDialog的Builder模式中并没有Director角色的出现。这里的AlertDialog.Builder同时扮演了Builder、ConcreteBuilder、Director的角色,简化了Builder模式的设计。
钩子方法的引入
建造者模式除了逐步构建了一个复杂产品对象外,还可以通过Director类来更加精细地控制产品的创建过程,例如增加一类称之为钩子方法(Hook Method)的特殊方法来控制是否调用某个buildPartX()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| public abstract class ComputerBuilder{ private Computer computer = new Computer(); public abstract void buildBoard(); public abstract void buildDisplay(); public abstract void buildOS(); public boolean isRetina(){ return false; } public Computer create(){ return computer; } }
public class MacbookBuilder extends ComputerBuilder{
@Override public void buildBoard(){ computer.setBoard("Intel"); } @Override public void buildDisplay(){ computer.setDisplay("Retina"); } @Override public void buildOS(){ computer.setOS("OS X 10.13"); } @Override public boolean isRetina(){ return true; } }
public class Director{ public Computer construct(ComputerBuilder computerbuilder){ Computer computer; computerbuilder.buildBoard(); if(computerbuilder.isRetina){ computerbuilder.buildDisplay(); } computerbuilder.buildOS(); computer = computerbuilder.create(); return computer; } }
|
建造者模式总结
优点
- 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
- 每一个具体建造者都相对独立,而与其他具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的新产品对象,符合开闭原则。
- 可以更精细地控制产品的创建过程。
缺点
- 建造者所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,就不适合使用建造者模式。
- 如果产品内部结构过于复杂,可能会定义过多的ConcreteBuilder类,消耗内存同时不易于维护。