1.定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。2.使用场景
(1)相同的方法,不同的执行顺序,产生不同的事件结果时。 (2)多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。 (3)产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个使用建造者模式非常适合。 (4)当初始化一个对象特别复杂,如参数多,且很多参数都具有默认值。3.构建模式的组成
• 抽象建造者角色(Builder):为创建一个Product对象的各个部件指定抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此角色规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。 • 具体建造者(ConcreteBuilder) 1)实现Builder的接口以构造和装配该产品的各个部件。即实现抽象建造者角色Builder的方法。 2)定义并明确它所创建的表示,即针对不同的商业逻辑,具体化复杂对象的各部分的创建 3) 提供一个检索产品的接口 4) 构造一个使用Builder接口的对象即在指导者的调用下创建产品实例 指导者(Director):调用具体建造者角色以创建产品对象的各个部分。指导者并没有涉及具体产品类的信息,真正拥有具体产品的信息是具体建造者对象。它只负责保证对象各部分完整创建或按某种顺序创建。 产品角色(Product):建造中的复杂对象。它要包含那些定义组件的类,包括将这些组件装配成产品的接口。4.简单实现
首先假设一个复杂对象是由多个部件组成的,Builder模式是把复杂对象的创建和部件的创建分别开来,分别用Builder类和Director类来表示。首先,需要一个接口,它定义如何创建复杂对象的各个部件
public interface Builder { //创建部件A 比如创建汽车车轮 void buildPartA(); //创建部件B 比如创建汽车方向盘 void buildPartB(); //创建部件C 比如创建汽车发动机 void buildPartC(); //返回最后组装成品结果 (返回最后装配好的汽车) //成品的组装过程不在这里进行,而是转移到下面的Director类中进行.从而实现了解耦过程和部件 Product getResult(); }用Director构建最后的复杂对象,而在上面Builder接口中封装的是如何创建一个个部件(复杂对象是由这些部件组成的),也就是说Director的内容是如何将部件最后组装成成品:
//Director 类,负责制造 public class Director { private Builder builder; public Director( Builder builder ) { this.builder = builder; } // 将部件partA partB partC最后组成复杂对象 //这里是将车轮 方向盘和发动机组装成汽车的过程 public void construct() { builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); } }Builder的具体实现ConcreteBuilder: 1.通过具体完成接口Builder来构建或装配产品的部件; 2.定义并明确它所要创建的是什么具体东西; 3.提供一个可以重新获取产品的接口。
public class ConcreteBuilder implements Builder { Part partA, partB, partC; public void buildPartA() { //这里是具体如何构建partA的代码 }; public void buildPartB() { //这里是具体如何构建partB的代码 }; public void buildPartC() { //这里是具体如何构建partB的代码 }; public Product getResult() { //返回最后组装成品结果 }; }复杂对象:产品Product
public interface Product { }复杂对象的部件
public interface Part { }如何调用Builder模式
//调用 Builder builder = new ConcreteBuilder(); Director director = new Director( builder ); director.construct(); Product product = builder.getResult(); 从上面可以看到由于Director封装了构建复杂的产品对象过程,对外隐藏了细节。 现实开发中,Director一般被省略。而直接使用一个Builder来进行对象的组装,这个Builder通常为链式调用,他是将setter方法返回自身。代码大致如下: new TestBuilder().setA("A").setB("B").create();5.Android源码中的Builder模式
以AlertDialog.Builder的源码为例(源码太长截取部分)
public static class Builder { private final AlertController.AlertParams P; private int mTheme; /** * Constructor using a context for this builder and the {@link AlertDialog} it creates. */ public Builder(Context context) { this(context, resolveDialogTheme(context, 0)); } /** * Constructor using a context and theme for this builder and * the {@link AlertDialog} it creates. The actual theme * that an AlertDialog uses is a private implementation, however you can * here supply either the name of an attribute in the theme from which * to get the dialog's style (such as {@link android.R.attr#alertDialogTheme} * or one of the constants * {@link AlertDialog#THEME_TRADITIONAL AlertDialog.THEME_TRADITIONAL}, * {@link AlertDialog#THEME_HOLO_DARK AlertDialog.THEME_HOLO_DARK}, or * {@link AlertDialog#THEME_HOLO_LIGHT AlertDialog.THEME_HOLO_LIGHT}. */ public Builder(Context context, int theme) { P = new AlertController.AlertParams(new ContextThemeWrapper( context, resolveDialogTheme(context, theme))); mTheme = theme; } /** * Returns a {@link Context} with the appropriate theme for dialogs created by this Builder. * Applications should use this Context for obtaining LayoutInflaters for inflating views * that will be used in the resulting dialogs, as it will cause views to be inflated with * the correct theme. * * @return A Context for built Dialogs. */ public Context getContext() { return P.mContext; } /** * Set the title displayed in the {@link Dialog}. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setTitle(CharSequence title) { P.mTitle = title; return this;//**这里返回自身,类似的来设置各种参数。 } // ......省略 /** * Creates a {@link AlertDialog} with the arguments supplied to this builder. It does not * {@link Dialog#show()} the dialog. This allows the user to do any extra processing * before displaying the dialog. Use {@link #show()} if you don't have any other processing * to do and want this to be created and displayed. */ public AlertDialog create() { final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false); P.apply(dialog.mAlert);//将P中的参数应用到dialog中的mAlert对象中 dialog.setCancelable(P.mCancelable); if (P.mCancelable) { dialog.setCanceledOnTouchOutside(true); } dialog.setOnCancelListener(P.mOnCancelListener); dialog.setOnDismissListener(P.mOnDismissListener); if (P.mOnKeyListener != null) { dialog.setOnKeyListener(P.mOnKeyListener); } return dialog; } /** * Creates a {@link AlertDialog} with the arguments supplied to this builder and * {@link Dialog#show()}'s the dialog. */ public AlertDialog show() { AlertDialog dialog = create(); dialog.show(); return dialog; } } 上面有个AlertController.AlertParams 的成员参数P,我们在Builder设置的title,icon等都储存在他里面。在调用create时在P.apply使用。6.总结
Builder模式在Android开发中较为常用,通常作为配置类的构建器将配置的构建和表示分离开来,同时也是将配置从目标类中隔离出来,避免过多的setter方法。Builder模式比较常见的实现形式是通过调用链实现,这样使得代码更简介、易懂。 可以参考ImageLoader的源代码,okhttputils请求Get分析的源代码。优点:
(1)良好的封装性,使用建造者模式可以使客户端不必知道产品内部组成细节。 (2)建造者独立,容易扩展。缺点:
会产生多余的Builder对象及Director对象,消耗内存。介绍完Builder模式,接下来讲讲设计模式中的第三种模式—-原型模式,敬请大家关注!!
参考来源: http://blog.csdn.net/qq_17766199/article/details/50250169