设计模式解析与实战之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();    } }

小结:可以隐藏细节,良好的封装性,易扩展。但是会产生多余对象耗内存。逗比的一天结束 了,坐等下班!!

0 0
原创粉丝点击