设计模式学习-Builder模式

2018-12-06  本文已影响0人  m1Ku

定义

Builder模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细的控制对象的构造过程。该模式是为了将复杂对象的构建过程和它的部件解耦,使得构建过程和部件的表示隔离开来。

UML图

Builder模式

Builder模式的角色

示例

以组装一辆车为例子,把组装车的流程简化成装配引擎、安装轮胎和组装车身三个步骤。

/**
 * 首先定义产品类
 * 产品类:汽车
 */
public class Car {
    private String engine;
    private String tire;
    private String body;

    public void setEngine(String engine) {
        this.engine = engine;
    }

    public void setTire(String tire) {
        this.tire = tire;
    }

    public void setBody(String body) {
        this.body = body;
    }

    @Override
    public String toString() {
        return "Car{" +
                "engine='" + engine + '\'' +
                ", tire='" + tire + '\'' +
                ", body='" + body + '\'' +
                '}';
    }
}

/**
 * Builder类
 * 规范构建流程
 */
public abstract class Builder {

    public abstract void buildEngine(String engine);

    public abstract void buildTire(String tire);

    public abstract void buildBody(String body);

    public abstract Car create();
    
}

/**
 * 具体的Builder类
 * 实现具体的构建流程
 */
public class CarBuilder extends Builder {
    Car car = new Car();

    @Override
    public void buildEngine(String engine) {
        car.setEngine(engine);
    }

    @Override
    public void buildTire(String tire) {
        car.setTire(tire);
    }

    @Override
    public void buildBody(String body) {
        car.setBody(body);
    }

    @Override
    public Car create() {
        return car;
    }
}

/**
 * Director类
 * 封装了构建产品对象的过程,对外隐藏构建细节
 */
public class Director {
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public void construct(String engine, String tire, String body) {
        builder.buildEngine(engine);
        builder.buildTire(tire);
        builder.buildBody(body);
    }
}

public static void main(String[]args){
        Builder builder = new CarBuilder();
        Director director = new Director(builder);
        director.construct("4AG","马牌轮胎","钢化车身");

        Car car = builder.create();
        System.out.println(car.toString());
    }

Car{engine='4AG', tire='马牌轮胎', body='钢化车身'}

Android源码中的Builder模式

AlterDialog对话框的构建就是用的Builder模式。如下在使用AlterDialog时,需要先初始化AlertDialog.Builder对象,然后通过这个Builder对象设置Dialog的相关参数,调用create方法创建AlterDialog对象,并调用show方法显示。

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("title")
        .setMessage("message")
        .setPositiveButton("confirm", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(MainActivity.this, "confirm click", Toast.LENGTH_SHORT).show();
            }
        });
AlertDialog alertDialog = builder.create();
alertDialog.show();

AlertDialog.Builder是AlterDialog的静态内部类,代码如下

public static class Builder {
    private final AlertParams P;
    private final int mTheme;

    public Builder(@NonNull Context context) {
        this(context, AlertDialog.resolveDialogTheme(context, 0));
    }

    public Builder(@NonNull Context context, @StyleRes int themeResId) {
        this.P = new AlertParams(new ContextThemeWrapper(context, AlertDialog.resolveDialogTheme(context, themeResId)));
        this.mTheme = themeResId;
    }

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

    public AlertDialog.Builder setTitle(@Nullable CharSequence title) {
            this.P.mTitle = title;
            return this;
    }
    
    public AlertDialog.Builder setMessage(@Nullable CharSequence message) {
        this.P.mMessage = message;
        return this;
    }
    // ...
}

在Builder对象的各个set方法中,又将值赋给了AlertParams对象的属性,AlertParams是AlterController的静态内部类,代码如下

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;
    //...
}

在Builder对象的相关构建方法完成后,调用了create方法生成AlterDialog对象,create方法如下

public AlertDialog create() {
    AlertDialog dialog = new AlertDialog(this.P.mContext, this.mTheme);
    this.P.apply(dialog.mAlert);
    dialog.setCancelable(this.P.mCancelable);
    if (this.P.mCancelable) {
        dialog.setCanceledOnTouchOutside(true);
    }

    dialog.setOnCancelListener(this.P.mOnCancelListener);
    dialog.setOnDismissListener(this.P.mOnDismissListener);
    if (this.P.mOnKeyListener != null) {
        dialog.setOnKeyListener(this.P.mOnKeyListener);
    }

    return dialog;
}

create方法中首先初始化AlertDialog对象,AlterDialog的构造方法如下

protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) {
    super(context, resolveDialogTheme(context, themeResId));
    this.mAlert = new AlertController(this.getContext(), this, this.getWindow());
}

在AlertDialog构造方法中会调用到其父类Dialog的构造方法

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
    if (createContextThemeWrapper) {
        if (themeResId == ResourceId.ID_NULL) {
            final TypedValue outValue = new TypedValue();
            context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
            themeResId = outValue.resourceId;
        }
        mContext = new ContextThemeWrapper(context, themeResId);
    } else {
        mContext = context;
    }

    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

    final Window w = new PhoneWindow(mContext);
    mWindow = w;
    w.setCallback(this);
    w.setOnWindowDismissedCallback(this);
    w.setOnWindowSwipeDismissedCallback(() -> {
        if (mCancelable) {
            cancel();
        }
    });
    w.setWindowManager(mWindowManager, null, null);
    w.setGravity(Gravity.CENTER);

    mListenersHandler = new ListenersHandler(this);
}

在Dialog构造方法中首先初始化PhoneWindow对象,然后将mWindowManager对象设置给mWindow对象。继续回到AlertDialog的构造方法中,传入context对象和window对象初始化了AlertController对象mAlert。AlertDialog构造方法中逻辑分析完了,回到create方法中,调用AlertParams的apply方法传入mAlter对象,代码如下

public void apply(AlertController dialog) {
    if (this.mCustomTitleView != null) {
        dialog.setCustomTitle(this.mCustomTitleView);
    } else {
        if (this.mTitle != null) {
            dialog.setTitle(this.mTitle);
        }

        if (this.mIcon != null) {
            dialog.setIcon(this.mIcon);
        }

        if (this.mIconId != 0) {
            dialog.setIcon(this.mIconId);
        }

        if (this.mIconAttrId != 0) {
            dialog.setIcon(dialog.getIconAttributeResId(this.mIconAttrId));
        }
    }

    if (this.mMessage != null) {
        dialog.setMessage(this.mMessage);
    }
    //...
}

在这个方法中,将AlertParams成员变量的值如mMessage等设值给了mAlter对象的成员变量。现在AlterDialog对象已经创建,并且相关参数已经设置到mAlter对象中,但是AlterDialog还没显示出来,而且相关参数值还未设置到AlterDialog的布局上,那接下来看下show方法显示AlterDialog的流程

public void show() {
    //...
    mCanceled = false;

    if (!mCreated) {
        dispatchOnCreate(null);
    } else {
        // Fill the DecorView in on any configuration changes that
        // may have occured while it was removed from the WindowManager.
        final Configuration config = mContext.getResources().getConfiguration();
        mWindow.getDecorView().dispatchConfigurationChanged(config);
    }

    onStart();
    mDecor = mWindow.getDecorView();
    //...
    mWindowManager.addView(mDecor, l);
   //...
}

dispatchOnCreate中回调Dialog的onCreate方法,该方法为空实现,具体实现由AlterDialog的onCreate完成,代码如下

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

这里具体逻辑交由mAlert的installContent方法处理

public void installContent() {
    int contentView = this.selectContentView();
    this.mDialog.setContentView(contentView);
    this.setupView();
}

方法中先是得到AlterDialog的布局,继而将通过setContentView将布局设置给AlterDialog,最后setupView方法就是将mAlert中的各成员变量设置到AlterDialog对应的view中

private void setupView() {
//...
    ViewGroup contentPanel = this.resolvePanel(customContentPanel, defaultContentPanel);
    this.setupContent(contentPanel);
//...
}

这里以设置mMessage属性为例,以下为setupContent代码,这里首先查找到mMessageView这个TextView,然后将mAlert的成员变量设置给了mMessageView。

private void setupContent(ViewGroup contentPanel) {
    //...
    this.mMessageView = (TextView)contentPanel.findViewById(16908299);
    if (this.mMessageView != null) {
        if (this.mMessage != null) {
            this.mMessageView.setText(this.mMessage);
        } else {
        //...  
        }
    }
}

show方法中最后调用WindowManager.addView方法添加了AlterDialog的Window,这样AlterDialog就显示出来了。

上一篇下一篇

猜你喜欢

热点阅读