设计模式之建造者模式

游乐园也来了

游乐园会有什么需求找到小明他们公司呢?现在游乐园需要根据顾客的不同要求为他们量身定做不同的主题假期,是量身定做哦~顾客可以选择假期天数、活动类型、是否需要住宿、餐饮、交通、一定要玩的项目等等。。。

小明认真的想了一下,这不很简单吗?一个主题都会有这些要求相应的参数,在构造时,使用一个构造函数,参数包括这一切要求就可以根据不同要求实例化了:

public class Vacation{
    int day;
    String type;
    boolean needHotal;
    boolean needTraffic;
    String[] mustProjects;
    String vacationPackage;

    public Vacation(int day, String type, boolean needHotal, boolean needTraffic, String[] mustProjects, String vacationPackage){
        this.day = day;
        this.type = type;
        this.needHotal = needHotal;
        this.needTraffic = needTraffic;
        this.mustProjects = mustProjects;
        this.vacationPackage = vacationPackage;
    }     

}

小明的主管说,你确定这样的设计可以吗?小明想了想,这样的确不太好。首先,构造函数的参数过多,会造成使用这个类的其他客户需要对每一个属性都必须明确它是否需要;第二,如果有新的属性加入,凡是使用到它的客户都需要做修改。所以我们将这一部分交给其他的类来处理,现在我们就需要使用到建造者模式,用建造者来负责这个对象的构建

抽象建造类:

public interface Builder {  
    public void setDay(int day);
    public void setType(String type);
    public void needHotal(boolean needHotal);
    public void this.needTraffic(boolean needTraffic);
    public void set mustProjects(String[] projects);
    public void set setVacationPackage(String vacationPackage);
    public Vacation create();  
}

具体建造类:

public class ConcreteBuilder implements Builder {  
    int day;
    String type;
    boolean needHotal;
    boolean needTraffic;
    String[] mustProjects;
    String vacationPackage;

    public void setDay(int day){
        this.day = day;
    }
    public void setType(String type){
        this.type = type;
    }
    public void needHotal(boolean needHotal){
        this.needHotal = needHotal;
    }
    public void needTraffic(boolean needTraffic){
        this.needTraffic = needTraffic;
    }
    public void set mustProjects(String[] projects){
        this.mustProjects = mustProjects;
    }
    public void set setPackage(String package){
        this.vacationPackage = vacationPackage;
    }
    public Vacation create(){

        Vacation vacation = new Vacation;

        if(day == 0) vacation.setDay(1);
        else vacation.setDay(day);

        if(type == null) vacation.setType("普通");
        else vacation.setType(type);

        else vacation.setNeedHotal(needHotal);

        else vacation.setNeedTraffic(needTraffic);

        else vacation.setMustProjects(mustProjects);

        else vacation.setVacationPackage(day);

        return vacation
    }
}

产品类:

public class Vacation{
    int day;
    String type;
    boolean needHotal;
    boolean needTraffic;
    String[] mustProjects;
    String vacationPackage;

    public void setDay(int day) {
        this.day = day;
    }

    public void setType(String type) {
        this.type = type;
    }

    public void setNeedHotal(boolean needHotal) {
        this.needHotal = needHotal;
    }

    public void setNeedTraffic(boolean needTraffic) {
        this.needTraffic = needTraffic;
    }

    public void setMustProjects(String[] mustProjects) {
        this.mustProjects = mustProjects;
    }

    public void setVacationPackage(String vacationPackage) {
        this.vacationPackage = vacationPackage;
    }    
}

创建产品:

public class Client {
    public static void main(String[]args){
        // 创建一个默认的产品
        Builder builderOne = new ConcreteBuilder();
        Vacation v1 = builderOne.create();

        // 一个5天需要酒店的产品
        Builder builderTwo = new ConcreteBuilder();
        builderTwo.setDay(5);
        builderTwo.needHotal(true);
        Vacation v2 = builderTwo.create();

        // 其他。。。    
    }
}

可以看到,我们再创建产品时就使用了建造者,在建造者中,我们可以在客户没有设置某个产品属性时,默认给产品添加相应的属性,这就是我们的建造者模式。停!这让我想到了抽象工厂模式,这不就是抽象工厂吗!一般情况下,建造者模式还有一个导演类,导演类的主要作用是和客户端打交道,也就是我们使用建造者模式创建产品的客户端并不直接与建造者打交道,而是通过导演类,这是建造者模式和抽象工厂一个很明显的区别,就这么点区别,当然不是,我们先看定义,再继续探讨他们的区别

定义

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

建造者模式

角色

  • 产品类
  • 抽象建造者
  • 建造者
  • 导演类

和抽象工厂的区别

除了多了一个导演类的区别,还有什么区别呢,其实导演类我们可以不需要,就像我们上面的例子,如果没有了导演类,它和我们的抽象工厂模式就更像了。一般的,抽象工厂是为了创建很复杂的产品,而建造者模式用于创建更为复杂的对象!甚至会引入导演类,导演类来负责产品的创建,而不是使用产品的客户端本身。另外,抽象工厂中一般产品的创建都会涉及到产品族

在Android中的建造者

大家一定在Android中使用过AlertDialog,AlertDialog的创建就是使用了建造者模式

public static class Builder {
    private final AlertController.AlertParams 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)));
    }

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

    public Builder setTitle(@StringRes int titleId) {
        P.mTitle = P.mContext.getText(titleId);
        return this;
    }

    public Builder setTitle(CharSequence title) {
        P.mTitle = title;
        return this;
    }

    public Builder setCustomTitle(View customTitleView) {
        P.mCustomTitleView = customTitleView;
        return this;
    }

    public Builder setMessage(@StringRes int messageId) {
        P.mMessage = P.mContext.getText(messageId);
        return this;
    }

    public Builder setMessage(CharSequence message) {
        P.mMessage = message;
        return this;
    }

    public Builder setIcon(@DrawableRes int iconId) {
        P.mIconId = iconId;
        return this;
    }

    public Builder setIcon(Drawable icon) {
        P.mIcon = icon;
        return this;
    }

    public Builder setIconAttribute(@AttrRes int attrId) {
        TypedValue out = new TypedValue();
        P.mContext.getTheme().resolveAttribute(attrId, out, true);
        P.mIconId = out.resourceId;
        return this;
    }

    public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) {
        P.mPositiveButtonText = P.mContext.getText(textId);
        P.mPositiveButtonListener = listener;
        return this;
    }

    public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
        P.mPositiveButtonText = text;
        P.mPositiveButtonListener = listener;
        return this;
    }

    public Builder setNegativeButton(@StringRes int textId, final OnClickListener listener) {
        P.mNegativeButtonText = P.mContext.getText(textId);
        P.mNegativeButtonListener = listener;
        return this;
    }

    public Builder setNegativeButton(CharSequence text, final OnClickListener listener) {
        P.mNegativeButtonText = text;
        P.mNegativeButtonListener = listener;
        return this;
    }

    public Builder setNeutralButton(@StringRes int textId, final OnClickListener listener) {
        P.mNeutralButtonText = P.mContext.getText(textId);
        P.mNeutralButtonListener = listener;
        return this;
    }

    public Builder setNeutralButton(CharSequence text, final OnClickListener listener) {
        P.mNeutralButtonText = text;
        P.mNeutralButtonListener = listener;
        return this;
    }

    public Builder setCancelable(boolean cancelable) {
        P.mCancelable = cancelable;
        return this;
    }

    public Builder setOnCancelListener(OnCancelListener onCancelListener) {
        P.mOnCancelListener = onCancelListener;
        return this;
    }

    public Builder setOnDismissListener(OnDismissListener onDismissListener) {
        P.mOnDismissListener = onDismissListener;
        return this;
    }

    public Builder setOnKeyListener(OnKeyListener onKeyListener) {
        P.mOnKeyListener = onKeyListener;
        return this;
    }

    public Builder setItems(@ArrayRes int itemsId, final OnClickListener listener) {
        P.mItems = P.mContext.getResources().getTextArray(itemsId);
        P.mOnClickListener = listener;
        return this;
    }

    public Builder setItems(CharSequence[] items, final OnClickListener listener) {
        P.mItems = items;
        P.mOnClickListener = listener;
        return this;
    }

    public Builder setAdapter(final ListAdapter adapter, final OnClickListener listener) {
        P.mAdapter = adapter;
        P.mOnClickListener = listener;
        return this;
    }

    public Builder setCursor(final Cursor cursor, final OnClickListener listener,
            String labelColumn) {
        P.mCursor = cursor;
        P.mLabelColumn = labelColumn;
        P.mOnClickListener = listener;
        return this;
    }

    public Builder setMultiChoiceItems(@ArrayRes int itemsId, boolean[] checkedItems,
            final OnMultiChoiceClickListener listener) {
        P.mItems = P.mContext.getResources().getTextArray(itemsId);
        P.mOnCheckboxClickListener = listener;
        P.mCheckedItems = checkedItems;
        P.mIsMultiChoice = true;
        return this;
    }

    public Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems,
            final OnMultiChoiceClickListener listener) {
        P.mItems = items;
        P.mOnCheckboxClickListener = listener;
        P.mCheckedItems = checkedItems;
        P.mIsMultiChoice = true;
        return this;
    }

    public Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn,
            final OnMultiChoiceClickListener listener) {
        P.mCursor = cursor;
        P.mOnCheckboxClickListener = listener;
        P.mIsCheckedColumn = isCheckedColumn;
        P.mLabelColumn = labelColumn;
        P.mIsMultiChoice = true;
        return this;
    }

    public Builder setSingleChoiceItems(@ArrayRes int itemsId, int checkedItem,
            final OnClickListener listener) {
        P.mItems = P.mContext.getResources().getTextArray(itemsId);
        P.mOnClickListener = listener;
        P.mCheckedItem = checkedItem;
        P.mIsSingleChoice = true;
        return this;
    }

    public Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn,
            final OnClickListener listener) {
        P.mCursor = cursor;
        P.mOnClickListener = listener;
        P.mCheckedItem = checkedItem;
        P.mLabelColumn = labelColumn;
        P.mIsSingleChoice = true;
        return this;
    }

    public Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener) {
        P.mItems = items;
        P.mOnClickListener = listener;
        P.mCheckedItem = checkedItem;
        P.mIsSingleChoice = true;
        return this;
    }

    public Builder setSingleChoiceItems(ListAdapter adapter, int checkedItem, final OnClickListener listener) {
        P.mAdapter = adapter;
        P.mOnClickListener = listener;
        P.mCheckedItem = checkedItem;
        P.mIsSingleChoice = true;
        return this;
    }

    public Builder setOnItemSelectedListener(final AdapterView.OnItemSelectedListener listener) {
        P.mOnItemSelectedListener = listener;
        return this;
    }

    public Builder setView(int layoutResId) {
        P.mView = null;
        P.mViewLayoutResId = layoutResId;
        P.mViewSpacingSpecified = false;
        return this;
    }

    public Builder setView(View view) {
        P.mView = view;
        P.mViewLayoutResId = 0;
        P.mViewSpacingSpecified = false;
        return this;
    }

    public Builder setRecycleOnMeasureEnabled(boolean enabled) {
        P.mRecycleOnMeasure = enabled;
        return this;
    }

    public AlertDialog create() {
        // Context has already been wrapped with the appropriate theme.
        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;
    }

    public AlertDialog show() {
        final AlertDialog dialog = create();
        dialog.show();
        return dialog;
    }
}

这个类是AlertDialog.java类中的一个静态内部类,我们一般使用AlertDialog就是通过它创建的,像这样:

AlertDialog alertDialog = new AlertDialog.Builder(this).setTitle("复选框").setMultiChoiceItems(new String[] { "Item1", "Item2" }, null, null).setPositiveButton("确定", null).setNegativeButton("取消", null).create();
// 或者
new AlertDialog.Builder(this).setTitle("复选框").setMultiChoiceItems(new String[] { "Item1", "Item2" }, null, null).setPositiveButton("确定", null).setNegativeButton("取消", null).show();

可以看到,对于AlertDialog,他有很多属性供我们自定义,这些属性的组合又会产生很多不同的AlertDialog,所以他很复杂,如果我们使用抽象工厂模式,我们的工厂类在我们的产品对象中也会导致我们的产品更复杂,所以我们在这种情况下,一般使用建造者模式去创建如此复杂的产品

坚持原创分享,您的支持将鼓励我不断前行!