设计模式解析与实战之Builder模式
来源:互联网 发布:域名投资的秘密 编辑:程序博客网 时间:2024/05/02 02:37
买了大神关爱民与何红辉所著书籍《设计模式解析与实战》,观后有所感、有所悟。
先来了解书中Builder模式的简单实现,抽象计算机类Computer:
public abstract class Computer { protected String mBoard; protected String mDisplay; protected String mOs; protected Computer() { super(); } public void setBoard(String mBoard) { this.mBoard = mBoard; } public void setDisplay(String mDisplay) { this.mDisplay = mDisplay; } public abstract void setOs(); @Override public String toString() { return "Computer [mBoard=" + mBoard + ", mDisplay=" + mDisplay + ", mOs=" + mOs + "]"; }}
具体计算机实现类Macbook:
public class Macbook extends Computer { @Override public void setOs() { mOs="mackbook OS X 10.11"; }}
抽象Builder类:
public abstract class Builder { public abstract void BuildBoard(String board); public abstract void BuildDisplay(String display); public abstract void BuildOS(); public abstract Computer create();}
具体实现类Macbook的集体Builder实现类:
public class MacbookBuilder extends Builder{ private Computer mComputer=new Macbook(); @Override public void BuildBoard(String board) { mComputer.setBoard(board); } @Override public void BuildDisplay(String display) { mComputer.setDisplay(display); } @Override public void BuildOS() { mComputer.setDisplay("mackbook OS x 10.11"); } @Override public Computer create() { return mComputer; }}
构造Computer的工具类:
/** * * 负责构造Computer * */public class Direcctor { Builder mBuilder=null; public Direcctor(Builder mBuilder){ this.mBuilder=mBuilder; } public void construct(String board,String display){ mBuilder.BuildBoard(board); mBuilder.BuildDisplay(display); mBuilder.BuildOS(); }}
测试类:
public class BuildTest { public static void main(String[] args) { Builder mBuilder=new MacbookBuilder(); Direcctor mDirecctor=new Direcctor(mBuilder); mDirecctor.construct("ios board", "ios display"); System.out.println(mBuilder.create().toString()); }}
测试结果:
Computer [mBoard=ios board, mDisplay=mackbook OS x 10.11, mOs=null]
简单的Builder模式demo完成,通过MacbookBuilder实现类构建Macbook实现内,对外隐藏了构建细节。在开发中我们常常遇到的Builder不是这样使用的,而是这样:
new Builder(this).setTitle("").setIcon(resId).create();
只需要把Builder的返回改成 return this;即可。下来看Android源码中的Builder模式的实现(AlertDialog):
public class AlertDialog extends Dialog implements DialogInterface { protected AlertDialog(Context context) { this(context, resolveDialogTheme(context, 0), true); } protected AlertDialog(Context context, int theme) { this(context, theme, true); } AlertDialog(Context context, int theme, boolean createThemeContextWrapper) { super(context, resolveDialogTheme(context, theme), createThemeContextWrapper); mWindow.alwaysReadCloseOnTouchAttr(); mAlert = new AlertController(getContext(), this, getWindow()); } protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) { super(context, resolveDialogTheme(context, 0)); mWindow.alwaysReadCloseOnTouchAttr(); setCancelable(cancelable); setOnCancelListener(cancelListener); mAlert = new AlertController(context, this, getWindow()); } }
根据以上源码可以发现获取AlertDialog实例时new 了一个AlertController,当我们调用new AlertDialog.Builder(this).setTitle(“”);实际作用是在给AlertController.AlertParams封装属性:
/** * Set the title displayed in the {@link Dialog}. * * @return This Builder object to allow for chaining of calls to set methods */ public Builder setTitle(CharSequence title) { P.mTitle = title; return this; }
当属性封装完成后调用了builder.create()方法创建了AlterDailog:
/** * Creates a {@link AlertDialog} with the arguments supplied to this builder. It does not * {@link Dialog#show()} the dialog. This allows the user to do any extra processing * before displaying the dialog. Use {@link #show()} if you don't have any other processing * to do and want this to be created and displayed. */ public AlertDialog create() { //构建AlertDialog final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false); //将builder的参数封装的AlertParams应用到AlertDialog实例出来的mAlert 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; }
下面是p.apply(mAlert)详细方法:
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) { dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText, mPositiveButtonListener, null); } if (mNegativeButtonText != null) { dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText, mNegativeButtonListener, null); } if (mNeutralButtonText != null) { dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText, mNeutralButtonListener, null); } // For a list, the client can either supply an array of items or an // adapter or a cursor 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); } /* dialog.setCancelable(mCancelable); dialog.setOnCancelListener(mOnCancelListener); if (mOnKeyListener != null) { dialog.setOnKeyListener(mOnKeyListener); } */ }
通过Builder封装AlertController.AlertParams的属性,封装完成后调用create方法构建AlertDialog,并将Builder封装好的params应用到controller,至于show dismiss方法就不扯远了,AlertDialog还有个亮点就是DialogInterface接口的设计,这里接口类内部再定义接口,这块涉及到架构设计这块的知识,如果想深入了解建议看高焕堂高老师的视频进阶,视频地址:http://www.maiziedu.com/course/androidjg/真不是打广告哈,我还在看这块的知识,觉的含金量比较高。
想到之前用过的xutils框架和imageLoad框架,再想到应用的缓存,瞅着前几天写的tab导航应用,Builder模式的实战demo有了,先说一下思路:应用缓存=首页tab关联缓存+商户tab关联缓存+活动tab关联缓存+用户信息tab缓存,通过builder构建Cache.先来看Cache类:
public class Cache { protected HomeCache mHomeCache; protected ShopCache mSHopCache; protected EventCache mEventCache; protected UserCache mUserCache; public void setHomeCache(HomeCache mHomeCache) { this.mHomeCache = mHomeCache; } public void setSHopCache(ShopCache mSHopCache) { this.mSHopCache = mSHopCache; } public void setEventCache(EventCache mEventCache) { this.mEventCache = mEventCache; } public void setUserCache(UserCache mUserCache) { this.mUserCache = mUserCache; } @Override public String toString() { return "Cache [mHomeCache=" + mHomeCache + ", mSHopCache=" + mSHopCache + ", mEventCache=" + mEventCache + ", mUserCache=" + mUserCache + "]"; }}
四个不同的Cache类这里就不累赘叙述,以HomeCache类为例:
public class HomeCache { protected String homeTitle; protected String homeUrl; protected String homeTagUrl; public HomeCache setHomeTitle(String homeTitle) { this.homeTitle = homeTitle; return this; } public HomeCache setHomeUrl(String homeUrl) { this.homeUrl = homeUrl; return this; } public HomeCache setHomeTagUrl(String homeTagUrl) { this.homeTagUrl = homeTagUrl; return this; } @Override public String toString() { return "HomeCache [homeTitle=" + homeTitle + ", homeUrl=" + homeUrl + ", homeTagUrl=" + homeTagUrl + "]"; }}
接下来定义OnConfigListener类(个人比较喜欢接口的方式,当然也可以像之前那样类直接写public 方法):
public interface OnConfigListener { CacheBuilder onConfigHome(HomeCache mHomeCache); CacheBuilder onConfigShop(ShopCache mShopCache); CacheBuilder onConfigEvent(EventCache mEventCache); CacheBuilder onConfigUser(UserCache mUserCache);}
现在轮到Builder类了,梳理依稀之前所学到的单例模式,这里综合实践吧,用到了容器单例和DCL单例,CacheBuilder类:
import java.util.HashMap;import java.util.Map;public class CacheBuilder implements OnConfigListener{ private static Map<String ,Cache> map=new HashMap<String,Cache>(); private static CacheBuilder instance; private static String cacheKey; public CacheBuilder() { } public static CacheBuilder getInstance(String name){ cacheKey=name; if(instance==null){ synchronized (CacheBuilder.class) { instance=new CacheBuilder(); } } return instance; } public static Cache getCache(String name){ Cache mCache=null; for(String key:map.keySet()){ if(key.equals(name)){ mCache=map.get(key); break; } } if(mCache==null){ synchronized (Cache.class) { if(mCache==null){ mCache=new Cache(); map.put(name, mCache); } } } return mCache; } @Override public CacheBuilder onConfigHome(HomeCache mHomeCache) { Cache mCache=getCache(cacheKey); mCache.setHomeCache(mHomeCache); return instance; } @Override public CacheBuilder onConfigShop(ShopCache mShopCache) { Cache mCache=getCache(cacheKey); mCache.setSHopCache(mShopCache); return instance; } @Override public CacheBuilder onConfigEvent(EventCache mEventCache) { Cache mCache=getCache(cacheKey); mCache.setEventCache(mEventCache); return instance; } @Override public CacheBuilder onConfigUser(UserCache mUserCache) { Cache mCache=getCache(cacheKey); mCache.setUserCache(mUserCache); return instance; } public Cache create(){ return getCache(cacheKey); }}
测试demo实例如下:
public class BuilderTest { public static void main(String[] args) { CacheBuilder mCacheBuilder=CacheBuilder.getInstance("app") .onConfigHome(new HomeCache() .setHomeTagUrl("tagUrl") .setHomeTitle("title") .setHomeUrl("url")) .onConfigShop(new ShopCache()) .onConfigEvent(new EventCache()) .onConfigUser(new UserCache()); Cache mCache=mCacheBuilder.create(); } }
小结:可以隐藏细节,良好的封装性,易扩展。但是会产生多余对象耗内存。逗比的一天结束 了,坐等下班!!
- 设计模式解析与实战之Builder模式
- 《Android源码设计模式解析与实战》——Builder模式
- 【读书笔记】Android源码设计模式解析与实战(三)——建造者模式(Builder)
- 设计模式解析与实战之单列模式
- 设计模式解析与实战之原型模式
- 设计模式解析与实战之工厂方法模式
- 设计模式解析与实战之策略模式
- 设计模式解析与实战之状态模式
- Android源码设计模式解析与实战之二单例模式
- Java设计模式实战-Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 设计模式之Builder
- 解决使用seletor点击改变背景时事件被上层布局获取的问题
- SpringMVC处理请求的流程
- java反射之二,使用java自带的jar实现
- redis(三) 持久化机制
- 二叉树遍历之递归实现(C++版)
- 设计模式解析与实战之Builder模式
- java前端框架总结
- Activity与Service通信的方式有三种
- 第十二周--数据结构--判断图G中是否存在边<i,j>
- 第十二届中国软件工程大会(CCSE 2015)相约北京!!有免费赠票啦
- android漏洞分析(整理)
- VS2012安装DirectX SDK(DXSDK_Feb10)
- 通达OA2015-缓存的使用
- Android中Context、Activity、Application之间有什么区别