Builder模式也叫建造者模式,属于创建性模式,一般用于复杂对象的创建
该模式可以将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离开来
该系列其他文章:
- 安卓设计模式(一)面向对象六大设计原则
- 安卓设计模式(二)单例模式
- 安卓设计模式(三)Builder模式
- 安卓设计模式(四)装饰者模式
- 安卓设计模式(五)代理模式
- 安卓设计模式(六)策略模式
- 安卓设计模式(七)模板方法模式
- 安卓设计模式(八)工厂方法模式
Android中的使用场景
-
复杂对象的创建,内部包含多个部件或者零件,都可以装配到一个对象中.如
AlertDialog.Builder()
new AlertDialog.Builder(this) .setPositiveButton("确定", null) .setTitle("请求权限") .setCancelable(false) .setMessage(messageResId) .show();
-
用于框架的初始化,初始化之后无法对框架内部数据再做改动.如
FileDownloader
框架的初始化:FileDownloadConfiguration.Builder builder = new FileDownloadConfiguration.Builder(this); builder.configFileDownloadDir(StorageUtils.getFilesDirectory(mContext).getAbsolutePath() + File.separator + "pdf"); builder.configRetryDownloadTimes(2); FileDownloadConfiguration configuration = builder.build(); FileDownloader.init(configuration);
创建或初始化对象时,参数多,并且参数都具有默认值.
用法
这里通过一个具体需求,一步一步来设计Builder模式
底部这个弹出框在很多页面会用到,我们就需要封装一下,叫做MenuDialog
,这里使用Dialog
来做(也可以用Popwindow
),分析这个dialog需求,特点如下:
- 从底部弹出,上面一行为分享组件(
ShareMenu
),是固定的,用于分享 - 第二行为一些具体操作的按钮
(ActionMenu
),并且第二行有时候是不需要的(隐藏) - 考虑到扩展性,
ActionMenu
的个数和每一个的图标和提示语(msg)应该是可定制的 -
ShareMenu
的点击事件就是调起分享,可以统一处理,ActionMenu
由于具体操作不同,应该暴露给调用者自行处理 -
ActionMenu
的图标和msg都应该有默认,"分享到"这个title也应该有默认并且可定制
数据存放 MenuDiaControl
在builder模式中,一般会有个存放数据的类Control,这里新建MenuDiaControl用于存放需要用到的参数
public class MenuDiaControl {
private Context mContext;
private String title = "分享到";
//share
private String mShareTitle = "";
private String mShareContent = "";
private String mShareImageUrl = "";
private String mShareUrl = "";
//action
private boolean mHineActionAll = false;//是否隐藏action操作栏
private List mBooleanList = new ArrayList<>();//单个action的按钮的图标和msg
private MoreMenuClickListener mListener;//Action回调
//geter and seter
}
内部类 Builder
Builder类是Builder模式中的主体操作类,接受配置参数并最后生成对象,具体实现如下:
public static class Builder {
private final MenuDiaControl mDiaControl;//存放参数
public Builder(Context context) {
mDiaControl = new MenuDiaControl(context);//初始化Control
}
/*<====================================公开的配置方法====================================================>*/
/**
* 设置title 默认="分享到"
*
* @param title
* @return
*/
public Builder title(String title) {
mDiaControl.setTitle(title);
return this;
}
//更多...(具体代码在文章最后)
/*<====================================公开的配置方法===================================================>*/
public MenuDialog build() {//生成对象
return new MenuDialog(mDiaControl);
}
}
对象 MenuDialog
即我们需要通过Builder模式创建的对象,最后的产出
public class MenuDialog extends Dialog {
//ButterKnife.bind..
private ShareUtils mShare;
private MenuDiaControl mControl;
private List mViewList = new ArrayList<>();
private MenuDialog(MenuDiaControl control) {
this(control.getContext(), R.style.CustomDialog);
mControl = control;
init();
}
private MenuDialog(Context context, int themeResId) {
super(context, themeResId);
}
private void init() { //setContentView
View diaView = View.inflate(mControl.getContext(), R.layout.dialog_post_operator, null);
setContentView(diaView);
ButterKnife.bind(this);
initWindow();
setContentView(diaView);
initView();
mShare = new ShareUtils(mControl.getContext()); //分享工具类
}
private void initView() { //根据Control中的参数,为对象设置各种属性
mTvTitle.setText(mControl.getTitle());
mViewList.add(mTvBackCircleList);
mViewList.add(mTvCopyUrl);
mViewList.add(mTvReport);
mViewList.add(mTvDelete);
for (int i = 0; i < mViewList.size(); i++) { //设置单个action
if (mControl.getBooleanList().get(i)) mViewList.get(i).setVisibility(View.INVISIBLE);
TextView textView = mViewList.get(i);
MenuBean menuBean = mControl.getMenuBeanList().get(i);
textView.setText(menuBean.getMsg());
Drawable drawable = mControl.getContext().getResources().getDrawable(menuBean.getIconRes());
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
textView.setCompoundDrawables(null, drawable, null, null);
}
mLlMore.setVisibility(mControl.isHineActionAll() ? View.GONE : View.VISIBLE);//是否隐藏ActionMenu
}
public static class Builder {
//Builder内部类...
}
private void initWindow() { //设置window的一些属性
setCancelable(false);
Window window = getWindow();
int width = LinearLayout.LayoutParams.MATCH_PARENT;
window.setLayout(width, LinearLayout.LayoutParams.WRAP_CONTENT);
window.setGravity(Gravity.BOTTOM);
setCanceledOnTouchOutside(true);
}
@OnClick({R.id.tv_wechat, R.id.tv_wechat_circle, R.id.tv_qq, R.id.tv_sina, R.id.tv_back_circle_list, R.id.tv_copy_url, R.id
.tv_report, R.id.tv_delete, R.id.btn_cancel})
public void onClick(View view) {
switch (view.getId()) {
case R.id.tv_wechat:
mShare.initShare(mControl.getShareTitle(), mControl.getShareContent(), mControl.getShareImageUrl(), mControl.getShareUrl
(), null);
mShare.setPlatform(Wechat.NAME);
mShare.startShare();
break;
//...执行统一的分享操作
case R.id.tv_back_circle_list: //Action具体操作回调给调用者
if (mControl.getListener() != null)
mControl.getListener().menuClick(0, this);
break;
case R.id.tv_copy_url:
if (mControl.getListener() != null)
mControl.getListener().menuClick(1, this);
break;
case R.id.tv_report:
if (mControl.getListener() != null)
mControl.getListener().menuClick(2, this);
break;
case R.id.tv_delete:
if (mControl.getListener() != null)
mControl.getListener().menuClick(3, this);
break;
case R.id.btn_cancel:
break;
}
dismiss();
}
}
使用
ok,一切都搞定后,我们看下使用方法,跟AlerterDialog的使用很像吧.我们使用Builder模式封装Menudialog,使用简单,链式调用,支持定制,在这个项目中是通用的,满足了上面的需求.
new MenuDialog.Builder(this)
.hideActionAll(false)//不隐藏ActionMenu
.shareData(new ShareBean(mInfoItem.getTitle(), mInfoItem.getSummary(), mInfoItem.getTitlePic(), mInfoItem.getUrl()))//设置分享数据
.setActionMenu(2,R.mipmap.icon,"msg")//制定ActionMenu
.title("设置title")
.hideAction4pos(3)//隐藏单个Action
.build()
//...
.show();
总结
Builder模式设计起来很简单,大家可以大胆的用到自己的项目或者框架中.
- Control类不是必须的,参数可以直接存放在Builder中,Android中很多Builder模式是省略Control的
- 上面的
R.style.CustomDialog
主要是用来使Dialog全屏的 - 上面的ShareBean是分享需要的参数实体
- ShareMenu也可以提供分享是否成功的回调,提供定制,等等待完善功能...
具体:
`
Builder类具体代码:
public static class Builder {
private final MenuDiaControl mDiaControl;
public Builder(Context context) {
mDiaControl = new MenuDiaControl(context);
}
/*<========================================================================================>*/
/**
* 设置title 默认="分享到"
*
* @param title
* @return
*/
public Builder title(String title) {
mDiaControl.setTitle(title);
return this;
}
/**
* 是否隐藏第二行的扩展操作按钮
* 默认不隐藏
*
* @param hide
* @return
*/
public Builder hideActionAll(boolean hide) {
mDiaControl.setHineActionAll(hide);
return this;
}
public Builder shareTitle(String title) {
mDiaControl.setShareTitle(title);
return this;
}
public Builder shareContent(String shareContent) {
mDiaControl.setShareContent(shareContent);
return this;
}
public Builder shareImageUrl(String shareImageUrl) {
mDiaControl.setShareImageUrl(shareImageUrl);
return this;
}
public Builder ShareUrl(String ShareUrl) {
mDiaControl.setShareUrl(ShareUrl);
return this;
}
/**
* 一次性设置分享需要的数据
*
* @param bean
* @return
*/
public Builder shareData(ShareBean bean) {
mDiaControl.setShareTitle(bean.getTitle());
mDiaControl.setShareContent(bean.getContent());
mDiaControl.setShareImageUrl(bean.getImageUrl());
mDiaControl.setShareUrl(bean.getUrl());
return this;
}
/**
* 设置底部某个menu的图标和msg
*
* @param position
* @param iconRes
* @param msg
* @return
*/
public Builder setActionMenu(int position, int iconRes, String msg) {
if (position < 0 || position > 3) return this;
mDiaControl.getMenuBeanList().set(position, new MenuBean(iconRes, msg, false));
return this;
}
/**
* 隐藏底部某个menu
*
* @param position
* @return
*/
public Builder hideAction4pos(int position) {
if (position < 0 || position > 3) return this;
mDiaControl.getBooleanList().set(position, true);
return this;
}
/**
* 底部menu的点击回调
*
* @param listener
* @return
*/
public Builder addActionMenuClick(MenuDiaControl.MoreMenuClickListener listener) {
mDiaControl.setListener(listener);
return this;
}
/*<========================================================================================>*/
/**
* 构造器
*
* @return
*/
public MenuDialog build() {
return new MenuDialog(mDiaControl);
}
}
关于作者
- 简 书:uncochen
- github:ChenZhen
- 新浪微博:@Chen丶振
- Email:[email protected]