美文网首页
设计模式之二 建造者(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