引言
见藐小之物必细察其纹理,故时有物外之趣。-------------------- 《童趣》
最近在写自己项目用上rxjava跟retrofit,然后就是一把梭。尽管"."就完事了实现功能之后就想了一下为什么可以这样操作。所以收集资料然后写下此篇。
什么是建造者模式(Builder)
先看一下我们的代码:
-
首先是一般的构造器:
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都是用到的建造者模式。
网友评论