Mode definition
Separates the construction of a complex object from its representation, so that different representations can be created during the same construction process.
Use Cases
1. When different event results are generated for the same method and different execution sequence;
2. Multiple parts or parts can be assembled into one object, but the running results are not the same;
3. The product class is very complex, or the calling sequence in the product class produces different performance. In this case, the builder mode is very suitable;
UML class diagram
Roles
Product: abstract class of the Product.
Builder: abstract class, which indicates the establishment of a standard product. Generally, a Child class implements a specific component process.
ConcreteBuilder: The specific builder.
Director: Unified assembly process (omitted ).
Simple Example
The following uses computer assembly as an example to demonstrate the simple and classic builder mode.
Package com. dp. example. builder;/*** Computer product abstract class. For example, only the attributes ** @ author mrsimple **/public abstract class Computer {protected int mCpuCore = 1 are listed; protected int mRamSize = 0; protected String mOs = "Dos"; protected Computer () {}// set the number of CPU cores public abstract void setCPU (int core ); // set the memory public abstract void setRAM (int gb); // set the OS public abstract void setOs (String OS); @ Overridepublic String toString () {return "Computer [mCpuCore =" + mCpuCore + ", mRamSize =" + mRamSize + ", mOs =" + mOs + "]" ;}} package com. dp. example. builder;/*** Apple Computer * @ author mrsimple **/public class AppleComputer extends Computer {protected AppleComputer () {}@ Overridepublic void setCPU (int core) {mCpuCore = core ;}@ Overridepublic void setRAM (int gb) {mRamSize = gb ;}@ Overridepublic void setOs (String OS) {mOs = OS ;}} package com. dp. example. builder;/*** builder abstract class ** @ author mrsimple **/public abstract class Builder {// set the number of CPU cores public abstract void buildCPU (int core ); // set the memory public abstract void buildRAM (int gb); // set the OS public abstract void buildOs (String OS); // create Computerpublic abstract Computer create ();} package com. dp. example. builder;/*** Apple Computer * @ author mrsimple **/public class AppleComputer extends Computer {protected AppleComputer () {}@ Overridepublic void setCPU (int core) {mCpuCore = core ;}@ Overridepublic void setRAM (int gb) {mRamSize = gb ;}@ Overridepublic void setOs (String OS) {mOs = OS ;}} package com. dp. example. builder;/*** builder abstract class ** @ author mrsimple **/public abstract class Builder {// set the number of CPU cores public abstract void buildCPU (int core ); // set the memory public abstract void buildRAM (int gb); // set the OS public abstract void buildOs (String OS); // create Computerpublic abstract Computer create ();} package com. dp. example. builder; public class ApplePCBuilder extends Builder {private Computer mApplePc = new AppleComputer (); @ Overridepublic void buildCPU (int core) {mApplePc. setCPU (core) ;}@ Overridepublic void buildRAM (int gb) {mApplePc. setRAM (gb) ;}@ Overridepublic void buildOs (String OS) {mApplePc. setOs (OS) ;}@ Overridepublic Computer create () {return mApplePc ;}} package com. dp. example. builder; public class Director {Builder mBuilder = null;/***** @ param builder */public Director (Builder builder) {mBuilder = builder ;} /*** build object ** @ param cpu * @ param ram * @ param OS */public void construct (int cpu, int ram, String OS) {mBuilder. buildCPU (cpu); mBuilder. buildRAM (ram); mBuilder. buildOs (OS) ;}}/*** classic implementation is cumbersome ** @ author mrsimple **/public class Test {public static void main (String [] args) {// Builder builder = new ApplePCBuilder (); // DirectorDirector pcdire= new Director (builder); // encapsulation construction process, 4 cores, 2 GB memory, mac system pcDirector. construct (4, 2, "Mac OS X 10.9.1"); // creates a computer and outputs information about the System. out. println ("Computer Info:" + builder. create (). toString ());}}
Build product objects through Builder, while Director encapsulates the process of building complex product objects, but the implementation is also cumbersome.
Source code analysis
In the Android source code, the most common Builder mode is AlertDialog. Builder, which is used to construct complex AlertDialog objects. A simple example is as follows:
- // Display the basic AlertDialog
- Private void showDialog (Context context ){
- AlertDialog. Builder builder = new AlertDialog. Builder (context );
- Builder. setIcon (R. drawable. icon );
- Builder. setTitle ("Title ");
- Builder. setMessage ("Message ");
- Builder. setPositiveButton ("Button1 ",
- New DialogInterface. OnClickListener (){
- Public void onClick (DialogInterface dialog, int whichButton ){
- SetTitle ("Click Button1 in the dialog box ");
- }
- });
- Builder. setNeutralButton ("Button2 ",
- New DialogInterface. OnClickListener (){
- Public void onClick (DialogInterface dialog, int whichButton ){
- SetTitle ("Click Button2 in the dialog box ");
- }
- });
- Builder. setNegativeButton ("Button3 ",
- New DialogInterface. OnClickListener (){
- Public void onClick (DialogInterface dialog, int whichButton ){
- SetTitle ("Click Button3 in the dialog box ");
- }
- });
- Builder. create (). show (); // build AlertDialog and display
- } Result:
Let's take a look at some of the source code of AlertDialog:
// AlertDialogpublic class AlertDialog extends Dialog implements DialogInterface {// Controller, accepts the private AlertController mAlert parameter in the Builder member variable P; // constructor protected alertdilic (Context context, int theme) {this (context, theme, true) ;}// 4: Construct AlertDialog (Context context, int theme, boolean createContextWrapper) {super (context, resolveDialogTheme (context, theme ), createContextWra Pper); mWindow. alwaysReadCloseOnTouchAttr (); mAlert = new AlertController (getContext (), this, getWindow ();} // actually calls the setTitle method of mAlert @ Override public void setTitle (CharSequence title) {super. setTitle (title); mAlert. setTitle (title);} // actually calling the setCustomTitle method of mAlert is public void setCustomTitle (View customTitleView) {mAlert. setCustomTitle (customTitleView);} public void setMessage (CharSequen Ce message) {mAlert. setMessage (message );} // other AlertDialog code is omitted. // ************* the internal class of AlertDialog is ************* * ***** public static class Builder {// 1: stores parameters of AlertDialog, such as title, message, and icon. private final AlertController. alertParams P; // attribute omitted/*** Constructor using a context for this builder and the {@ link AlertDialog} it creates. */public Builder (Context context) {this (contex T, resolveDialogTheme (context, 0);} public Builder (Context context, int theme) {P = new AlertController. alertParams (new ContextThemeWrapper (context, resolveDialogTheme (context, theme); mTheme = theme;} // other Builder code is omitted ...... // 2: set various parameters public Builder setTitle (CharSequence title) {P. mTitle = title; return this;} public Builder setMessage (CharSequence message) {P. mMessage = message; r Eturn this;} public Builder setIcon (int iconId) {P. mIconId = iconId; return this;} public Builder setPositiveButton (CharSequence text, final OnClickListener listener) {P. mPositiveButtonText = text; P. mPositiveButtonListener = listener; return this;} public Builder setView (View view) {P. mView = view; P. mViewSpacingSpecified = false; return this;} // 3: Construct AlertDialog and pass the public AlertDialog parameter. Create () {// call new AlertDialog to construct the object, and pass the parameter to the individual AlertDialog final AlertDialog dialog = new AlertDialog (P. mContext, mTheme, false); // 5: Apply the parameters in P to the mAlert object in the diert. apply (dialog. mAlert); dialog. setCancelable (P. mCancelable); if (P. mCancelable) {dialog. setCanceledOnTouchOutside (true);} dialog. setOnCancelListener (P. mOnCancelListener); if (P. mOnKeyListener! = Null) {dialog. setOnKeyListener (P. mOnKeyListener) ;}return dialog ;}}}
You can see that the title, message, button and other parameters in AlertDialog are set through Builder. These parameters are stored in the AlertController type. in the member variable P of AlertParams, AlertController. alertParams contains the corresponding member variables. AlertDialog is created only when the create function of the Builder class is called, and the parameters saved in the Builder member variable P are applied to the mAlert object of AlertDialog, that is, P. apply (dialog. mAlert) code segment. Let's take a look at the implementation of the apply function:
public void apply(AlertController dialog) { if (mCustomTitleView != null) { dialog.setCustomTitle(mCustomTitleView); } else { if (mTitle != null) { dialog.setTitle(mTitle); } if (mIcon != null) { dialog.setIcon(mIcon); } if (mIconId >= 0) { dialog.setIcon(mIconId); } if (mIconAttrId > 0) { dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId)); } } if (mMessage != null) { dialog.setMessage(mMessage); } if (mPositiveButtonText != null) { dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText, mPositiveButtonListener, null); } if (mNegativeButtonText != null) { dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText, mNegativeButtonListener, null); } if (mNeutralButtonText != null) { dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText, mNeutralButtonListener, null); } if (mForceInverseBackground) { dialog.setInverseBackgroundForced(true); } // For a list, the client can either supply an array of items or an // adapter or a cursor if ((mItems != null) || (mCursor != null) || (mAdapter != null)) { createListView(dialog); } if (mView != null) { if (mViewSpacingSpecified) { dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, mViewSpacingBottom); } else { dialog.setView(mView); } } }
In fact, it is to set the parameters in P to AlertController one by one, that is, the mAlert object in AlertDialog. From the setter methods of AlertDialog, we can also see that the setter methods corresponding to mAlert are also called. Here, Builder also plays the roles of builder, ConcreteBuilder, and Director mentioned above, simplifying the design of the Builder mode.
Advantages and disadvantagesAdvantages:1. Good encapsulation. Using the builder mode, the client does not have to know the details of the product's internal composition; 2. the builder is independent and easy to expand; 3. Some other objects in the system will be used during object creation. These objects are not easy to obtain during product object creation.
Disadvantages:1. Redundant Builder objects and ctor objects will be generated, consuming memory; 2. Exposing the object building process.