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 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 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 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 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吧!

你可能感兴趣的:(Jianwoo中的设计模式(3) — Builder模式)