美文网首页
设计模式之二 建造者(Builder)

设计模式之二 建造者(Builder)

作者: 就爱烫卷发 | 来源:发表于2019-01-26 15:44 被阅读0次

    引言

    见藐小之物必细察其纹理,故时有物外之趣。-------------------- 《童趣》

        最近在写自己项目用上rxjava跟retrofit,然后就是一把梭。尽管"."就完事了实现功能之后就想了一下为什么可以这样操作。所以收集资料然后写下此篇。

    什么是建造者模式(Builder)

        先看一下我们的代码:

    1. 首先是一般的构造器:
          
      public Person(String name,String age,String sex);类似于这种的代码在我们的项目中是很常见的,我们用这个来构造一个有参对象,调用的时候只需要get 就可以得到对应的值,行吧两个参数咋可以搞定那么三个呢,四个呢。。。20个呢。。所以这个时候直接构造函数就不行了。那么我们会采用什么
      Persion persion = new Persion(); persion.setName(); persion.setAge();
          这是我们常用的手段,但是调用一些系统的API的时候:

      AlertDialog alertDialog = new AlertDialog.Builder(this).create();
      alertDialog.setTitle("");
      alertDialog.setIcon(R.drawable.a);
      

        这是什么个操作 怎么跟我们之前使用的不一样。我们点进去看看。

     public static class Builder {
        private final AlertParams P;
        private final int mTheme;
    
        public Builder(@NonNull Context context) {
            this(context, AlertDialog.resolveDialogTheme(context, 0));
        }
        //这里省去部分代码 只截取其中的一部分 这里的setTitle 跟setIcon setView 一样 都是返回的this。
        public AlertDialog.Builder setTitle(@StringRes int titleId) {
            this.P.mTitle = this.P.mContext.getText(titleId);
            return this;
        }
    

        这是builder 然后我们看看后面的Create是个啥:

           public AlertDialog create() {
            AlertDialog dialog = new AlertDialog(this.P.mContext, this.mTheme);
            this.P.apply(dialog.mAlert);
            dialog.setCancelable(this.P.mCancelable);
            if (this.P.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
    
            dialog.setOnCancelListener(this.P.mOnCancelListener);
            dialog.setOnDismissListener(this.P.mOnDismissListener);
            if (this.P.mOnKeyListener != null) {
                dialog.setOnKeyListener(this.P.mOnKeyListener);
            }
            //这边直接返回的是一个dialog 也就是我们刚开始new 的对象
            return dialog;
        }
    

            看上去好像就是多了些Build和Create() 然后后面的用法跟之前的并没有什么差异反而看上去更麻烦了。Google这样设计肯定有他的道理,我们肯定看过一些代码 比如:

            new AlertDialog.Builder(this)
                .setIcon(R.mipmap.ic_launcher)
                .setMessage("Hello World")
                .setTitle("Test")
                .create()
                .show();
    

            这样就可以直接弹出一个对话框,这样是不是就很舒服 很快了 结构也非常的清晰。这就是们的Builder 的一个例子。

    为什么用建造者

            如果一个对象要很多参数,默认的或者不定的,就可以然后用上述的例子来初始化。

    如何使用

            我们看一个例子,首先要有一个具体的Builder 这里我写成类似菜单,名字,价钱,做的时间,几桌

     public abstract class Builder {
           public abstract void Name(String name);
           public abstract void Cost(String cost);
           public abstract void Time(String time);
           public abstract void Table();
           public abstract Menu createMenu(); 
     }
    

            再来一个对象

    public abstract class Menu {
    protected String name ;
    protected String cost;
    protected String time;
    protected String table;
    
    public Menu() {
    }
    //我们得要知道是哪桌点的菜吧
    public abstract void setTable();
    //set()/get()省掉。
    
    @Override
    public String toString() {
        return "Menu{" +
                "name='" + name + '\'' +
                ", cost='" + cost + '\'' +
                ", time='" + time + '\'' +
                ", table='" + table + '\'' +
                '}';
    }
    }
    

            好了 现在第一桌来了 ,我们要记一下第一桌的情况

    public class FirstMenu extends Menu {
    public FirstMenu() {
    }
    @Override
    public void setTable() {
       table = "第一桌";
     }
    }
    

            有对象,有上面FirstMenu的抽象实现方法,我们需要一个set方法吧,那来吧

    public class MenuBuilder extends Builder {
    private Menu menu = new FirstMenu();
    @Override
    public void Name(String name) {
        menu.setName(name);
    }
    @Override
    public void Cost(String cost) {
        menu.setCost(cost);
    }
    @Override
    public void Time(String time) {
         menu.setTime(time);
    }
    @Override
    public void Table() {
        menu.setTable();
    }
    //注意这里返回的是menu 是不是跟上面 new AlertDialog.Builder(this).create(); 这个create() 有联想
    @Override
    public Menu createMenu() {
      return menu;
    }
    }
    

            这下菜单有了,怎么设置有了,那么来个设置点菜的吧,来个服务员吧。 (专业术语这个角色叫Director)

    public class Waiter {
    
    Builder builder =null;
    
    public Waiter(Builder builder) {
        this.builder = builder;
       }
    public void construct(String name  , String cost ,String time){
        builder.Name(name);
        builder.Cost(cost);
        builder.Time(time);
        builder.Table();
        }
    }
    

            ok角色到齐了,那么怎么让他们动起来呢。

        private void Test(){
          Builder builder = new MenuBuilder();
          Waiter waiter = new Waiter(builder);
          waiter.construct("韭菜炒鸡蛋","18","5分钟");
        //这边就能打印出第一桌 然后上述的三个
        }
    

            这些就是简单的Builder 的使用例子,以后第二桌第三桌若干桌,只要继续一下,自己手动写一下第几桌然后就可以让服务员过来点菜了。(智能一点的就不需要自己写第几桌,也让服务员写 也就是把Menu里面的setTable()方法给弄成跟name,cost 一样的形式)。这样的好像变的更加复杂了。想想,我明明可以写一个对象自己设置就完事了。。而且也是用的上面的construct(),远不如我对象直接来构造器。好吧我们可能要修改一下。
    我们来吧MenuBuilder中的方法改成如下形式:

       @Override
       public MainBuilderOne Name(String name) {
          menu.setName(name);
          return this;
        }
    

    借助于上面的思想

        AlertDialog.Builder setTitle(@StringRes int titleId) {
        this.P.mTitle = this.P.mContext.getText(titleId);
        return this;
    

    好了咋们现在也可以直接一把梭

     new MainBuilder()
                .Cost("12")
                .Name("西红柿鸡蛋面")
                .Time("10分钟")
                .Table()
                .createMenu());
    

    总结

            XXX.XXX().XXXX() 这种操作在敲代码的时候很常用的,我们这样理解一下就不仅仅会用一些别人封装好的方法,我们还可以知道他内部的实现,原来这边是这样设计的,让我们在枯燥的写代码的时候能有一些新奇的感受。不至于那么枯燥。下面还有几个常见的如有兴趣可以去看看源码设计。这里再贴一个简单封装的HtppManager:

        public class HttpManager {
         //超时时长
          public static final int DEFAULT_TIME_OUT = 5;
          public static final int DEFAULT_TIME = 10;
          private Retrofit retrofit ;
          /**
           * 初始化http 各种
           */
          private HttpManager() {
              OkHttpClient.Builder builder = new OkHttpClient.Builder();
              builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);
              builder.readTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);
              builder.writeTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);
              retrofit = new Retrofit.Builder()
                      .client(builder.build())
                      .baseUrl(GeeksApis.HOST)
                      .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                      .addConverterFactory(GsonConverterFactory.create())
                      .build();
          }
          private static class SingletonHolder{
              private static final HttpManager INSTANCE = new HttpManager();
          }
          public static HttpManager getInstance(){
              return SingletonHolder.INSTANCE;
          }
          public <T> T create(Class<T> service){
              return retrofit.create(service);
          }
     }
    

    用到了单例,然后HTTPClient 和Retrofit2都是用到的建造者模式。

    相关文章

      网友评论

          本文标题:设计模式之二 建造者(Builder)

          本文链接:https://www.haomeiwen.com/subject/bzuijqtx.html