Android Design Patterns - Builder Patterns

Posted by dhe on Sun, 19 May 2019 04:22:01 +0200

Preface

Android Design Patterns Series: Welcome your attention and keep updating:

1. definition

Separating the construction of a complex object from its representation enables the same construction process to create different representations.

2. introduction

  • The builder model belongs to the creation model.
  • Builder mode is mainly used to create complex objects, users can not care about its construction process and details.
  • For example, when we want to assemble a computer, we choose CPU, memory, hard disk and so on, and then give it to the assembler. The assembler will assemble the computer. We don't need to care how to assemble it.

3.UML class diagram

Role description:
  • Product (product class): Complex objects to be created. In this class diagram, the product class is a concrete class, not an abstract class. In practical programming, a product class can be composed of an abstract class and its different implementations, or it can be composed of several abstract classes and their implementations.
  • Builder (abstract builder): To create abstract interfaces for products, there is usually at least one abstract method for creating products and one abstract method for returning products. Abstract classes are introduced to make it easier to extend.
  • ConcreteBuilder (Actual Builder): Inherits the Builder class and implements all abstract methods of the abstract class. Realize the specific construction process and details.
  • Director (Commander Class): Assign different builders to create products and unify assembly processes.

4. implementation

4.1 Define specific Product categories: computers

public class Computer {
    private String mCPU;
    private String mMemory;
    private String mHD;

    public void setCPU(String CPU) {
        mCPU = CPU;
    }

    public void setMemory(String memory) {
        mMemory = memory;
    }

    public void setHD(String HD) {
        mHD = HD;
    }
}

4.2 Definition of an abstract Builder: The process of assembling a computer

public abstract class Builder {
    public abstract void buildCPU(String cpu);//Assemble CPU

    public abstract void buildMemory(String memory);//Assembly memory

    public abstract void buildHD(String hd);//Assemble hard disk

    public abstract Computer create();//Return to the assembled computer
}

4.3 Create Concrete Builder: Installer

public class ConcreteBuilder extends Builder {
    //Create product instances
    private Computer mComputer = new Computer();

    @Override
    public void buildCPU(String cpu) {//Assemble CPU
        mComputer.setCPU(cpu);
    }

    @Override
    public void buildMemory(String memory) {//Assembly memory
        mComputer.setMemory(memory);
    }

    @Override
    public void buildHD(String hd) {//Assemble hard disk
        mComputer.setHD(hd);
    }

    @Override
    public Computer create() {//Return to the assembled computer
        return mComputer;
    }
}

4.4 Define Director: The Boss Delegates Tasks to the Installer

public class Director {
    private Builder mBuild = null;

    public Director(Builder build) {
        this.mBuild = build;
    }

    //Command Installers to Assemble Computers
    public void Construct(String cpu, String memory, String hd) {
        mBuild.buildCPU(cpu);
        mBuild.buildMemory(memory);
        mBuild.buildHD(hd);
    }
}

4.5 Test Method

   public void CreatComputer() {
        Builder builder = new ConcreteBuilder();//Create an instance of the builder. (Installer)
        Director direcror = new Director(builder);//Create commander instances and assign builders accordingly. (Boss assigns tasks)
        direcror.Construct("i7-6700", "Samsung DDR4", "Seagate 1 T");//Assemble computer
    }

5. Application scenarios

  • When creating complex objects, there are complex changes in the process of building objects.
  • The same construction process, different execution order, produce different results.
  • When different configurations of building objects produce different results.

6. advantages

  • Good encapsulation, hiding internal build details.
  • It is easy to decouple and decouple the product itself from the product creation process. The same creation process can be used to get different products. That is to say, details depend on abstraction.
  • Easy to expand, specific builder classes are independent of each other, adding new specific builders without modifying the original library code.
  • It is easy to precisely control the creation of objects, because the specific builder is independent, so it can gradually refine the construction process, without any impact on other modules.

7. disadvantages

  • Generate redundant Build objects and Dirextor classes.
  • The products created by the builder model generally have many similarities, and their components are similar. If there are great differences among products, it is not suitable to use the builder model, so its scope of use is limited.
  • If the internal changes of products are complex, it may lead to the need to define many specific builder classes to achieve such changes, resulting in a huge system.

8. Source code analysis in Android

AlertDialog.Builder in Android uses the Builder pattern to build AlertDialog.

8.1 Simple Use of AlertDialog.Builder
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);//Create a Builder object
        builder.setIcon(R.drawable.icon);
        builder.setTitle("Title");
        builder.setMessage("information");
        builder.setPositiveButton("Sure?",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                });
        AlertDialog alertDialog = builder.create();//Create an AlertDialog object
        alertDialog.show();//Show Alert Dialog

Builder objects are used to build Icon, Title, Message and so on, hiding the construction process and details of AlertDialog.

8.2 Alert Dialog Related Source Code Analysis
//AlertDialog source code
public class AlertDialog extends Dialog implements DialogInterface {
    private AlertController mAlert;//Accept the parameters of Builder member variable P

    AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0, createContextThemeWrapper);
        mWindow.alwaysReadCloseOnTouchAttr();
        mAlert = AlertController.create(getContext(), this, getWindow());//Create an AlertController object
    }

    @Override
    public void setTitle(CharSequence title) {//Set Title
        super.setTitle(title);
        mAlert.setTitle(title);//Save it in the AlertController object
    }

    public void setMessage(CharSequence message) {//Setting Message
        mAlert.setMessage(message);//Save it in the AlertController object
    }

    public void setIcon(@DrawableRes int resId) {//Set Icon
        mAlert.setIcon(resId);//Save it in the AlertController object
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();//Install the contents of AlertDialog
    }

    //Alert Dialog Other Codes

    public static class Builder {
        private final AlertController.AlertParams P;//The parameters needed to build the AlertDialog object are stored in P

        public Builder(Context context) {
            this(context, resolveDialogTheme(context, 0));
        }

        public Builder(Context context, int themeResId) {
            P = new AlertController.AlertParams(new ContextThemeWrapper(
                    context, resolveDialogTheme(context, themeResId)));//Initialize the AlertParams object
        }

        public Context getContext() {
            return P.mContext;
        }

        public android.app.AlertDialog.Builder setTitle(CharSequence title) {
            P.mTitle = title;//Save title to P
            return this;
        }

        public android.app.AlertDialog.Builder setMessage(CharSequence message) {
            P.mMessage = message;//Save message
            return this;
        }


        public android.app.AlertDialog.Builder setIcon(@DrawableRes int iconId) {
            P.mIconId = iconId;//Save IconId
            return this;
        }

        //Other Builder Codes

        public android.app.AlertDialog create() {//Building Alert Dialog
            final android.app.AlertDialog dialog = new android.app.AlertDialog(P.mContext, 0, false);//Create an AlertDialog object
            P.apply(dialog.mAlert);//Set the parameters in P to Alert Controller
            //Other settings
            return dialog;
        }
    }
}
//Dialog source code
 public class Dialog implements DialogInterface, Window.Callback, KeyEvent.Callback, View.OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
        //Other code outlines
        public void show() {
            //The preceding code is outlined
            if (!mCreated) {
                dispatchOnCreate(null);//Distribution of onCreate
            } else {
                final Configuration config = mContext.getResources().getConfiguration();
                mWindow.getDecorView().dispatchConfigurationChanged(config);
            }

            onStart();//Call onStart()
            mDecor = mWindow.getDecorView();

            //Setting Parametric Layout Parameters

            mWindowManager.addView(mDecor, l);//Add to Windows Manager
            mShowing = true;

            sendShowMessage();
        }

        void dispatchOnCreate(Bundle savedInstanceState) {//Distribution of onCreate
            if (!mCreated) {
                onCreate(savedInstanceState);//Call the onCreate method of AlertDialog to create the AlertDialog view
                mCreated = true;
            }
        }
    }
//Alert Controller source code
public class AlertController {
        //Other code outlines

        public void installContent() {//Installation contents
            int contentView = selectContentView();//Choose the right layout
            mWindow.setContentView(contentView);//Layout added to Window s
            setupView();//Add the elements that need to be built in the dialog.mAlert object to Window s one by one, that is to say, building the layout we set takes place in this step.
        }
    }
8.3 Simple process description:
  1. After setting various attributes (such as setTitle()) through AlertDialog.Builder, these attribute information will be stored in the P variable, the type of P variable is AlertController.AlertParams.
  2. Calling builder.create() returns an AlertDialog object.
    2.1 The builder. create () method first creates an AlertDialog object, which initializes Windows Manager and Windows when constructed.
    2.2 After the AlertDialog object is created by builder. create (), P.apply(dialog.mAlert) is called; that is, the elements stored in the P variable to construct the AlertDialog object are set to dialog.mAlert, and the dialog.mAlert type is AlertController.

  3. Call the show() method of AlertDialog to show the interface.
    3.1 The show () method calls dispatchOnCreate(null), dispatchOnCreate(null) calls onCreate(),onCreate() calls mAlert.installContent(); that is, install the contents of AlertDialog.
    3.2 The mWindow.setContentView (mAlert Dialog Layout) is called in installContent (); that is, the mAlert Dialog Layout layout is added to Windows.
    3.3 After calling mWindow.setContentView (mAlert DialogLayout), setupView() will be added to mWindows one by one.
    3.4 is finally shown by adding view to mWindows Manager.

8.4 Summary:
  • The builder pattern hides this complex build process, showing Alert Dialog in just a few lines of simple code.
  • There are no abstract builders, directors and other roles in the builder of Alert Dialog. AlertDialog.Builder also plays the roles of Builder, ConcreteBuilder, Director and so on, which is a simplification of Android and worth learning and using.

Topics: Android Windows Programming Attribute