设计模式->建造者模式

33 阅读5分钟

我正在参与掘金创作者训练营第6期,点击了解活动详情

建造者模式

建造者模式(Bulider Pattern)是将一个复杂对象的构建过程与它的实现表示分离,使得同样的构建过程可以创建不同的表示,属于创建型模式。使用创建者模式对于用户而言只需要制定需要建造的类就可以获得对象,建造过程及细节不需要了解。

建造者模式中涉及到的角色

  • 设计者->调用具体的建造者,来创建对象的各个部分,在调用者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建
  • 产品->要创建的产品对象
  • 建造者抽象(Builder) ->工人接口,定义了各个工人所需要进行的工作,并不负责具体的建造
  • 建造者 ->具体的Builder类,根据不同的业务逻辑,具体化对象的各个组成部分的创建。

以建房子为例:

设计者

public class Designer {
    public Room build(Build build){
        build.makeWindow();
        build.makFloor();
        return build.build();
    }
}

建造者抽象(Builder)

public interface Build {
    public void makeWindow();
    public void makFloor();
    public Room build();
}

产品

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 + '\'' +
                '}';
    }
}

建造者

public class WorkBuilder implements Build {
    private Room room=new Room();
    @Override
    public void makeWindow() {
        room.setWindow("法式窗户");
    }
    @Override
    public void makFloor() {
        room.setFloor("实木地板");
    }
    @Override
    public Room build() {
        return room;
    }
}

建房子的过程

   Build worker=new WorkBuilder();
   Designer designer=new Designer();
   Room room=designer.build(worker);
   System.out.println(room);

建造者模式的应用场景

建造者模式适用于一个具有较多的零件的复杂产品的创建过程,由于需求的变化,组成这个复杂产品的各个零件经常猛烈变化,但是他们的组合方式却相对稳定。
建造者模式适用于以下的几种场景:
1、相同的方法,不同的执行顺序,产生不用的结果时
2、多个部件或者零件,都可以装配到一个对象中,但是产生的结果又不相同
3、产品非常复杂,或者产品类中的调用顺序不用产生不同的作用
4、当时初始化一个对象特别复杂,参数多,而且很多参数都具有默认值时\

Android源码中建造者模式使用

dialog的构建就是采用了建造者模式

Dialog的简单使用

AlertDialog.Builder(this)
    .setTitle("title")
    .setMessage("Message")
    .create()
    .show()

进入AlertDialog类的Builder方法

private final AlertController.AlertParams P;

public Builder(Context context) {
    this(context, resolveDialogTheme(context, Resources.ID_NULL));
}

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

这个方法是给P这个变量赋值,AlertController.AlertParams是AlertController类中一个一个静态内部类,AlertController.AlertParams里面主要是定义了一些和dialog相关的属性和回掉监听的方法

public static class AlertParams {
    public final Context mContext;
    public final LayoutInflater mInflater;

    public int mIconId = 0;
    public Drawable mIcon;
    public int mIconAttrId = 0;
    public CharSequence mTitle;
    public View mCustomTitleView;
    public CharSequence mMessage;
    public CharSequence mPositiveButtonText;
    public Drawable mPositiveButtonIcon;
    public DialogInterface.OnClickListener mPositiveButtonListener;
    public CharSequence mNegativeButtonText;
    public Drawable mNegativeButtonIcon;
    public DialogInterface.OnClickListener mNegativeButtonListener;
    public CharSequence mNeutralButtonText;
    public Drawable mNeutralButtonIcon;
    public DialogInterface.OnClickListener mNeutralButtonListener;
    public boolean mCancelable;
    public DialogInterface.OnCancelListener mOnCancelListener;
    public DialogInterface.OnDismissListener mOnDismissListener;
    public DialogInterface.OnKeyListener mOnKeyListener;
    public CharSequence[] mItems;
    public ListAdapter mAdapter;
    public DialogInterface.OnClickListener mOnClickListener;
    public int mViewLayoutResId;
    public View mView;
    public int mViewSpacingLeft;
    public int mViewSpacingTop;
    public int mViewSpacingRight;
    public int mViewSpacingBottom;
    public boolean mViewSpacingSpecified = false;
    public boolean[] mCheckedItems;
    public boolean mIsMultiChoice;
    public boolean mIsSingleChoice;
    public int mCheckedItem = -1;
    public DialogInterface.OnMultiChoiceClickListener mOnCheckboxClickListener;
    public Cursor mCursor;
    public String mLabelColumn;
    public String mIsCheckedColumn;
    public boolean mForceInverseBackground;
    public AdapterView.OnItemSelectedListener mOnItemSelectedListener;
    public OnPrepareListViewListener mOnPrepareListViewListener;
    public boolean mRecycleOnMeasure = true;

    public interface OnPrepareListViewListener {
        void onPrepareListView(ListView listView);
    }

    public AlertParams(Context context) {
        mContext = context;
        mCancelable = true;
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
    //这个会在调用create方法时调用
    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 || mPositiveButtonIcon != null) {
            dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
                    mPositiveButtonListener, null, mPositiveButtonIcon);
        }
        if (mNegativeButtonText != null || mNegativeButtonIcon != null) {
            dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
                    mNegativeButtonListener, null, mNegativeButtonIcon);
        }
        if (mNeutralButtonText != null || mNeutralButtonIcon != null) {
            dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
                    mNeutralButtonListener, null, mNeutralButtonIcon);
        }
        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);
            }
        } else if (mViewLayoutResId != 0) {
            dialog.setView(mViewLayoutResId);
        }
    }

    private void createListView(final AlertController dialog) {
        final RecycleListView listView =
                (RecycleListView) mInflater.inflate(dialog.mListLayout, null);
        final ListAdapter adapter;

        if (mIsMultiChoice) {
            if (mCursor == null) {
                adapter = new ArrayAdapter<CharSequence>(
                        mContext, dialog.mMultiChoiceItemLayout, android.R.id.text1, mItems) {
                    @Override
                    public View getView(int position, View convertView, ViewGroup parent) {
                        View view = super.getView(position, convertView, parent);
                        if (mCheckedItems != null) {
                            boolean isItemChecked = mCheckedItems[position];
                            if (isItemChecked) {
                                listView.setItemChecked(position, true);
                            }
                        }
                        return view;
                    }
                };
            } else {
                adapter = new CursorAdapter(mContext, mCursor, false) {
                    private final int mLabelIndex;
                    private final int mIsCheckedIndex;

                    {
                        final Cursor cursor = getCursor();
                        mLabelIndex = cursor.getColumnIndexOrThrow(mLabelColumn);
                        mIsCheckedIndex = cursor.getColumnIndexOrThrow(mIsCheckedColumn);
                    }

                    @Override
                    public void bindView(View view, Context context, Cursor cursor) {
                        CheckedTextView text = (CheckedTextView) view.findViewById(
                                android.R.id.text1);
                        text.setText(cursor.getString(mLabelIndex));
                        listView.setItemChecked(cursor.getPosition(),
                                cursor.getInt(mIsCheckedIndex) == 1);
                    }

                    @Override
                    public View newView(Context context, Cursor cursor, ViewGroup parent) {
                        return mInflater.inflate(dialog.mMultiChoiceItemLayout,
                                parent, false);
                    }

                };
            }
        } else {
            final int layout;
            if (mIsSingleChoice) {
                layout = dialog.mSingleChoiceItemLayout;
            } else {
                layout = dialog.mListItemLayout;
            }

            if (mCursor != null) {
                adapter = new SimpleCursorAdapter(mContext, layout, mCursor,
                        new String[] { mLabelColumn }, new int[] { android.R.id.text1 });
            } else if (mAdapter != null) {
                adapter = mAdapter;
            } else {
                adapter = new CheckedItemAdapter(mContext, layout, android.R.id.text1, mItems);
            }
        }

        if (mOnPrepareListViewListener != null) {
            mOnPrepareListViewListener.onPrepareListView(listView);
        }
        dialog.mAdapter = adapter;
        dialog.mCheckedItem = mCheckedItem;

        if (mOnClickListener != null) {
            listView.setOnItemClickListener(new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                    mOnClickListener.onClick(dialog.mDialog, position);
                    if (!mIsSingleChoice) {
                        dialog.mDialog.dismiss();
                    }
                }
            });
        } else if (mOnCheckboxClickListener != null) {
            listView.setOnItemClickListener(new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                    if (mCheckedItems != null) {
                        mCheckedItems[position] = listView.isItemChecked(position);
                    }
                    mOnCheckboxClickListener.onClick(
                            dialog.mDialog, position, listView.isItemChecked(position));
                }
            });
        }

        if (mOnItemSelectedListener != null) {
            listView.setOnItemSelectedListener(mOnItemSelectedListener);
        }
        if (mIsSingleChoice) {
            listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        } else if (mIsMultiChoice) {
            listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        }
        dialog.mListView = listView;
    }
}

进入AlertDialog类中的create方法

public AlertDialog create() {
    final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
    P.apply(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;
}

进入dialog的show方法

public void show() {
    if (mShowing) {
        if (mDecor != null) {
            if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
            }
            mDecor.setVisibility(View.VISIBLE);
        }
        return;
    }

    mCanceled = false;

    if (!mCreated) {
        dispatchOnCreate(null);
    } else {
        final Configuration config = mContext.getResources().getConfiguration();
        mWindow.getDecorView().dispatchConfigurationChanged(config);
    }

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

    if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
        final ApplicationInfo info = mContext.getApplicationInfo();
        mWindow.setDefaultIcon(info.icon);
        mWindow.setDefaultLogo(info.logo);
        mActionBar = new WindowDecorActionBar(this);
    }

    WindowManager.LayoutParams l = mWindow.getAttributes();
    boolean restoreSoftInputMode = false;
    if ((l.softInputMode
            & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
        l.softInputMode |=
                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
        restoreSoftInputMode = true;
    }

    mWindowManager.addView(mDecor, l);
    if (restoreSoftInputMode) {
        l.softInputMode &=
                ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
    }

    mShowing = true;

    sendShowMessage();
}

进入Dialog类中的dispatchOnCreate方法

void dispatchOnCreate(Bundle savedInstanceState) {
    if (!mCreated) {
        onCreate(savedInstanceState);
        mCreated = true;
    }
}
protected void onCreate(Bundle savedInstanceState) {
}

onCreate 的具体处理逻辑应该在子类AlertDialog中

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mAlert.installContent();
}

mAlert其实就是我们开头进入的AlertController类

public void installContent() {
    final int contentView = selectContentView();
    mDialog.setContentView(contentView);
    //布局相关
    setupView();
}

里面最主要的是setupView方法,里面涉及到一些dialog中空间的一些初始化等操作

private void setupView() {
    final View parentPanel = mWindow.findViewById(R.id.parentPanel);
    final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
    final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
    final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);

    final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
    setupCustomContent(customPanel);

    final View customTopPanel = customPanel.findViewById(R.id.topPanel);
    final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
    final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);

    final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
    final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
    final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);

    setupContent(contentPanel);
    setupButtons(buttonPanel);
    setupTitle(topPanel);

    final boolean hasCustomPanel = customPanel != null
            && customPanel.getVisibility() != View.GONE;
    final boolean hasTopPanel = topPanel != null
            && topPanel.getVisibility() != View.GONE;
    final boolean hasButtonPanel = buttonPanel != null
            && buttonPanel.getVisibility() != View.GONE;

    if (!hasButtonPanel) {
        if (contentPanel != null) {
            final View spacer = contentPanel.findViewById(R.id.textSpacerNoButtons);
            if (spacer != null) {
                spacer.setVisibility(View.VISIBLE);
            }
        }
    }

    if (hasTopPanel) {
        if (mScrollView != null) {
            mScrollView.setClipToPadding(true);
        }

        View divider = null;
        if (mMessage != null || mListView != null) {
            divider = topPanel.findViewById(R.id.titleDividerNoCustom);
        }

        if (divider != null) {
            divider.setVisibility(View.VISIBLE);
        }
    } else {
        if (contentPanel != null) {
            final View spacer = contentPanel.findViewById(R.id.textSpacerNoTitle);
            if (spacer != null) {
                spacer.setVisibility(View.VISIBLE);
            }
        }
    }

    if (mListView instanceof RecycleListView) {
        ((RecycleListView) mListView).setHasDecor(hasTopPanel, hasButtonPanel);
    }

    if (!hasCustomPanel) {
        final View content = mListView != null ? mListView : mScrollView;
        if (content != null) {
            final int indicators = (hasTopPanel ? ViewCompat.SCROLL_INDICATOR_TOP : 0)
                    | (hasButtonPanel ? ViewCompat.SCROLL_INDICATOR_BOTTOM : 0);
            setScrollIndicators(contentPanel, content, indicators,
                    ViewCompat.SCROLL_INDICATOR_TOP | ViewCompat.SCROLL_INDICATOR_BOTTOM);
        }
    }

    final ListView listView = mListView;
    if (listView != null && mAdapter != null) {
        listView.setAdapter(mAdapter);
        final int checkedItem = mCheckedItem;
        if (checkedItem > -1) {
            listView.setItemChecked(checkedItem, true);
            listView.setSelection(checkedItem);
        }
    }
}

大致的时序图

image.png