Jianwoo中的设计模式(3) — Builder模式

前言

高仿Pinterest交互的实现思路这篇文章中,其实对于封装后的入口类,是需要提供很多参数的,那对于需要设置很多参数的类,我们如果全部在方法中提供set方法来设置,那将会显得非常凌乱,这个时候应该要将提供参数的方法封装起来作为一个单独的类,然后供给需要这些参数的产品类,这样可以统一提供参数入口,让这个本来需要参数就多的类减少与外部的调用关系,即方便日后扩展自身功能又不影响到与外部的调用

简物中的Builder模式

高仿Pinterest交互入口类在没有使用Builder模式是怎么传参的呢?以下为部分代码

public class PinterestSelector implements PinterestSelectorContent.OnTouchToSelectorListener, PinterestSelectorContent.OnItemSelectListener{

    int mScrollViewId;
    View mView;
    View mItemLayout;
    boolean onlyShowItemLayout;
    String mShowItemViewBackgroundColor;
    List<ITouchView> mITouchViews;

    ....

    private PinterestSelector(){
    }

    /**
     * 该方法调用不存在线程安全问题
     */
    public static PinterestSelector newInstance(){
        if(instance == null){
            instance = new PinterestSelector();
        }
        return instance;
    }

    public PinterestSelector scroll(int scrollviewId){
        this.mScrollViewId = scrollviewId;
        return this;
    }

    /**
     * 设置长按item时候周边的背景色
     * eg: #f2ffffff
     * @param color
     * @return
     */
    public PinterestSelector backgroundColor(String color){
        this.mShowItemViewBackgroundColor = color;
        return this;
    }

    public PinterestSelector show(View itemLayout){
        this.mItemLayout = itemLayout;
        this.onlyShowItemLayout = true;
        return this;
    }

    public PinterestSelector addITouchView(ITouchView iTouchView){
        if(mITouchViews == null){
            mITouchViews = new ArrayList<>();
        }
        this.mITouchViews.add(iTouchView);
        return this;
    }

    public PinterestSelector addITouchViews(List<ITouchView> iTouchViews){
        this.mITouchViews.clear();
        this.mITouchViews.addAll(iTouchViews);
        return this;
    }

    ....

}

调用方式为

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(!v.isClickable()){
            return false;
        }
        PinterestSelector.newInstance().
                show((View)v.getParent()).
                scroll(getBindId()).
                backgroundColor("#f0ffffff").
                addITouchView(new ShoppingCartPinterestViewFactory().create()).
                addITouchView(new LikePinterestViewFactory().withLike(getAdapter().getItem(position).isLike()).create()).
                setOnLongClickListener(new PinterestSelector.OnLongClickListener() {
                @Override
                public void onLongClick(View v) {
                    handleLongClick();
                }
                }).
                setOnCancelListener(new PinterestSelector.OnCancelListener() {
                @Override
                public void onCancel() {
                }

                @Override
                public void onSyncCancel() {
                    handleSyncCancel();
                }
                }).
                setOnItemSelectListener(new PinterestSelector.OnItemSelectListener() {
                    @Override
                    public void onItemSelect(int index) {
                        switch (index){
                            case IPinterestView.LIKE:
                                handleCollectSelect();
                                break;
                            case IPinterestView.CART:
                                handleSlideToCart();
                                break;
                        }
                    }
                }).
                onTouch(v, event);
}

其实也是链式编程调用形式,但这样有什么弊端呢,我需要在PinterestSelector产品类维护大量供外界调用的方法,如果哪个函数中赋值变量的地方需要修改,那大量调用这个类的地方都要修改,这不是我所希望的,我希望在我维护PinterestSelector产品的时候不因为内部功能的修改而牵扯到外部类的调用,类与类之间调用关系越密切,其耦合度约会越来越大,我们学习编程的时候总是听到什么“低耦合、高内聚”,无论是做什么功能,各个模块之间的耦合度应该尽量降低,六大设计原则中有一条叫“迪米特法则”,另一种叫法叫“最少知道原则”说的就是这个意思
那对于这种情况我们应该怎么做呢,我们应该单独建一个类,作为建造者类提供外界设置参数,然后将设置好的参数“打包”给产品类,这样外界与产品之间的供给关系就交给建造者去完成了,产品做了什么内部修改,都不影响参数的传递,如果后面有什么新的参数增加,那也只需要在建造者内添加即可,打包的入口不用做任何修改,添加赋值即可
那我们应该这样修改代码:

public class PinterestSelector implements PinterestSelectorContent.OnTouchToSelectorListener, PinterestSelectorContent.OnItemSelectListener{

    int mScrollViewId;
    View mView;
    View mItemLayout;
    boolean onlyShowItemLayout;
    String mShowItemViewBackgroundColor;
    List<ITouchView> mITouchViews;

    ....

    private PinterestSelector(){
    }

    /**
     * 该方法调用不存在线程安全问题
     */
    public static PinterestSelector newInstance(){
        if(instance == null){
            instance = new PinterestSelector();
        }
        return instance;
    }

    public PinterestSelector with(Builder builder){
        this.mItemLayout = builder.mItemView;
        this.mScrollViewId = builder.mScrollViewId;
        this.mShowItemViewBackgroundColor = builder.mColor;
        this.mITouchViews = builder.mITouchViews;
        this.onLongClickListener = builder.mOnLongClickListener;
        this.onCancelListener = builder.mOnCancelListener;
        this.onItemSelectListener = builder.mOnItemSelectListener;
        this.mDialogMode = builder.mDialogMode;
        return this;
    }

    public static class Builder {

        /**
         * Dialog模式
         */
        private boolean mDialogMode;

        /**
         * 空白部分之外要显示的View
         */
        private View mItemView;

        /**
         * 当前选中view外层可滚动的view(如果没有就是Activity)
         */
        private int mScrollViewId;

        /**
         * 不显示区域背景色
         */
        private String mColor;

        /**
         * TouchViews
         */
        private List<IPinterestView> mITouchViews;

        /**
         * 长按监听
         */
        private PinterestSelector.OnLongClickListener mOnLongClickListener;

        /**
         * 选择监听
         */
        private OnItemSelectListener mOnItemSelectListener;

        /**
         * 退出监听
         */
        private OnCancelListener mOnCancelListener;

        public Builder(){
            mITouchViews = new ArrayList<>();
        }

        /**
         * 空白部分外部的view
         * @param itemView
         */
        public Builder show(View itemView){
            this.mItemView = itemView;
            return this;
        }

        public Builder scroll(int viewId){
            this.mScrollViewId = viewId;
            return this;
        }

        public Builder backgroundColor(String color){
            this.mColor = color;
            return this;
        }

        public Builder addITouchView(IPinterestView iTouchView){
            if(mITouchViews != null){
                mITouchViews.add(iTouchView);
            }
            return this;
        }

        public Builder setOnLongClickListener(OnLongClickListener onLongClickListener){
            this.mOnLongClickListener = onLongClickListener;
            return this;
        }

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

        public Builder setOnItemSelectListener(PinterestSelector.OnItemSelectListener onItemSelectListener){
            this.mOnItemSelectListener = onItemSelectListener;
            return this;
        }

        public Builder dialogMode() {
            this.mDialogMode = true;
            return this;
        }

        public PinterestSelector create(){
            return PinterestSelector.newInstance().with(this);
        }

        ....

    }

那外部的调用就变成这样了

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(!v.isClickable()){
            return false;
        }
        new PinterestSelector.Builder()
                .show((View)v.getParent())
                .scroll(getBindId())
                .backgroundColor("#f0ffffff")
                .dialogMode()
                .addITouchView(new ShoppingCartPinterestViewFactory().create())
                .addITouchView(new LikePinterestViewFactory().withLike(getAdapter().getItem(position).isLike()).create())
                .setOnLongClickListener(new PinterestSelector.OnLongClickListener() {
                    @Override
                    public void onLongClick(View v) {
                        handleLongClick();
                    }
                })
                .setOnCancelListener(new PinterestSelector.OnCancelListener() {
                    @Override
                    public void onCancel() {
                    }

                    @Override
                    public void onSyncCancel() {
                        handleSyncCancel();
                    }
                })
                .setOnItemSelectListener(new PinterestSelector.OnItemSelectListener() {
                    @Override
                    public void onItemSelect(int index) {
                        switch (index){
                            case IPinterestView.LIKE:
                                handleCollectSelect();
                                break;
                            case IPinterestView.CART:
                                handleSlideToCart();
                                break;
                        }
                    }
                })
                .create()
                .onTouch(v, event);

        return super.onTouch(v, event);
    }

这样一修改是不是觉得这个功能的两个模块非常清晰,传参的模块只负责接收外部类提供的参数,而产品类只需要给参数赋值并且做自己的产品实现,其它的与外界没有任何关联,这就是Builder模式的巧妙之处!
Android中有什么地方用到了Builder模式呢,最常见的就是AlertDialog,在AlertDialog使用中我们这样写过(以下代码来自网络

protected void showDialog() {
   AlertDialog.Builder builder = new Builder(Main.this);
   builder.setMessage("确认退出吗?");
   builder.setTitle("提示");
   builder.setPositiveButton("确认", new OnClickListener() {
       @Override
       public void onClick(DialogInterface dialog, int which) {
           dialog.dismiss();
           Main.this.finish();
       }
   });
   builder.setNegativeButton("取消", new OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
        }
   });
   builder.create().show();
}

还有OkHttp的创建也用到了Builder模式

OkHttpClient okHttpClient = new OkHttpClient.Builder()
                 .cache(getCache()) 
                 .addInterceptor(new HttpCacheInterceptor())
                 .addInterceptor(new LogInterceptor())
                 .addNetworkInterceptor(new HttpRequestInterceptor()) 
                 .build();

好了,现在你对Builder(建造者)模式应该也有一个大概的了解了,如果你喜欢这篇文章,那请不要吝啬给个like吧!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • 面向对象的六大原则 单一职责原则 所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于...
    JxMY阅读 923评论 1 3
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,889评论 1 15
  • 没有人买车会只买一个轮胎或者方向盘,大家买的都是一辆包含轮胎、方向盘和发动机等多个部件的完整汽车。如何将这些部件组...
    justCode_阅读 1,818评论 1 6
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 原文链接:http://blog.csdn.net/zhangerqing http://www.cnblogs....
    孤独杂货铺阅读 1,507评论 0 3