设计模式之Builder模式

参与者

  • Builder
    为创建一个Product对象的各个部件指定抽象接口。
  • ConcreteBuilder
    实现Builder的接口以构造和装配该产品的各个部件。
    定义并明确它所创建的表示。
    提供一个检索产品的接口
  • Director
    构造一个使用Builder接口的对象。
  • Product
    表示被构造的复杂对象。ConcreateBuilder创建该产品的内部表示并定义它的装配过程。
    包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

使用场景

产品复杂,且它允许使用者不必知道内部构建细节的情况下使用。
注意:现实开发过程中,Director角色经常会被省略。直接使用Builder来进对象的组装,这个Builder通常为链式调用,它的关键点是每个方法都返回自身 - return this,这使得set方法可以链式调用,代码如下:
Test test = new Test.Builder().setA("A").setB("B").create();

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/** "Product" */
class Pizza {
private String dough = "";
private String sauce = "";
private String topping = "";

public void setDough (String dough) { this.dough = dough; }
public void setSauce (String sauce) { this.sauce = sauce; }
public void setTopping (String topping) { this.topping = topping; }
}


''/** "Abstract Builder" */''
abstract class PizzaBuilder {
protected Pizza pizza;

public Pizza getPizza() { return pizza; }
public void createNewPizzaProduct() { pizza = new Pizza(); }

public abstract void buildDough();
public abstract void buildSauce();
public abstract void buildTopping();
}

/** "ConcreteBuilder" */
class HawaiianPizzaBuilder extends PizzaBuilder {
public void buildDough() { pizza.setDough("cross"); }
public void buildSauce() { pizza.setSauce("mild"); }
public void buildTopping() { pizza.setTopping("ham+pineapple"); }
}

/** "ConcreteBuilder" */
class SpicyPizzaBuilder extends PizzaBuilder {
public void buildDough() { pizza.setDough("pan baked"); }
public void buildSauce() { pizza.setSauce("hot"); }
public void buildTopping() { pizza.setTopping("pepperoni+salami"); }
}


''/** "Director" */''
class Waiter {
private PizzaBuilder pizzaBuilder;

public void setPizzaBuilder (PizzaBuilder pb) { pizzaBuilder = pb; }
public Pizza getPizza() { return pizzaBuilder.getPizza(); }

public void constructPizza() {
pizzaBuilder.createNewPizzaProduct();
pizzaBuilder.buildDough();
pizzaBuilder.buildSauce();
pizzaBuilder.buildTopping();
}
}

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
/** A customer ordering a pizza. */
class BuilderExample {
public static void main(String[] args) {
Waiter waiter = new Waiter();
PizzaBuilder hawaiian_pizzabuilder = new HawaiianPizzaBuilder();
PizzaBuilder spicy_pizzabuilder = new SpicyPizzaBuilder();

waiter.setPizzaBuilder ( hawaiian_pizzabuilder );
waiter.constructPizza();

Pizza pizza = waiter.getPizza();
}
}

实际场景举一例

okhttputils请求Get分析

1
2
3
4
5
6
String url = "http://www.csdn.net/";
OkHttpUtils
.get()
.url(url)
.build()
.execute(new MyStringCallback());

首先看到这里有个build(),估计就是建造模式了,摸进去一看,没有错。

.get()进去一看,果然不假

1
2
3
4
public static GetBuilder get()
{
return new GetBuilder();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class GetBuilder extends OkHttpRequestBuilder
{
@Override
public RequestCall build()
{
if (params != null)
{
url = appendParams(url, params);
}

return new GetRequest(url, tag, params, headers).build();
}
// ...
@Override
public GetBuilder url(String url)
{
this.url = url;
return this;
}
// ...
}

这里设定了url,且看到已经看到了build()方法,基本和最初的判定一致,是Builder模式,但这跟Okhttp用法还是有差距,继续跟进,发现最初.get()的GetBuilder直接将设置的数据全部扔进OkHttpRequest了 - 这、、、

1
2
3
4
5
6
7
8
9
10
11
12
public class GetRequest extends OkHttpRequest
{
public GetRequest(String url, Object tag, Map<String, String> params, Map<String, String> headers)
{
super(url, tag, params, headers);
}
// ...
@Override
protected Request buildRequest(Request.Builder builder, RequestBody requestBody)
{
return builder.get().build();
}

尼玛,坑啊,build()没有?继续

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public abstract class OkHttpRequest
{
protected String url;
protected Object tag;
protected Map<String, String> params;
protected Map<String, String> headers;
protected Request.Builder builder = new Request.Builder();
protected OkHttpRequest(String url, Object tag,
Map<String, String> params, Map<String, String> headers)
{
this.url = url;
this.tag = tag;
this.params = params;
this.headers = headers;

if (url == null)
{
Exceptions.illegalArgument("url can not be null.");
}
}
// ...
protected abstract Request buildRequest(Request.Builder builder, RequestBody requestBody);
public RequestCall build()
{
return new RequestCall(this);
}
public Request generateRequest(Callback callback)
{
RequestBody requestBody = wrapRequestBody(buildRequestBody(), callback);
prepareBuilder();
return buildRequest(builder, requestBody);
}

private void prepareBuilder()
{
builder.url(url).tag(tag);
appendHeaders();
}
// ...
}

终于看到我辛苦设置的参数都在这里了,返回了RequestCall,也看到眼熟的Requset.Builder,但目前还是没有看到谁调用了,看来还得继续深入RequestCall

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class RequestCall
{
private OkHttpRequest okHttpRequest;
private Request request;
private Call call;
// ...
private OkHttpClient clone;

public RequestCall(OkHttpRequest request)
{
this.okHttpRequest = request;
}
// ...

public Call generateCall(Callback callback)
{
request = generateRequest(callback);

if (readTimeOut > 0 || writeTimeOut > 0 || connTimeOut > 0)
{
readTimeOut = readTimeOut > 0 ? readTimeOut : OkHttpUtils.DEFAULT_MILLISECONDS;
writeTimeOut = writeTimeOut > 0 ? writeTimeOut : OkHttpUtils.DEFAULT_MILLISECONDS;
connTimeOut = connTimeOut > 0 ? connTimeOut : OkHttpUtils.DEFAULT_MILLISECONDS;

clone = OkHttpUtils.getInstance().getOkHttpClient().newBuilder()
.readTimeout(readTimeOut, TimeUnit.MILLISECONDS)
.writeTimeout(writeTimeOut, TimeUnit.MILLISECONDS)
.connectTimeout(connTimeOut, TimeUnit.MILLISECONDS)
.build();

call = clone.newCall(request);
} else
{
call = OkHttpUtils.getInstance().getOkHttpClient().newCall(request);
}
return call;
}

private Request generateRequest(Callback callback)
{
return okHttpRequest.generateRequest(callback);
}

public void execute(Callback callback)
{
generateCall(callback);

if (callback != null)
{
callback.onBefore(request);
}

OkHttpUtils.getInstance().execute(this, callback);
}
// ...

public Response execute() throws IOException
{
generateCall(null);
return call.execute();
}
// ...
}

在这里可以看到Client,request,call了,OkHttpUtils.getInstance().getOkHttpClient()request = generateRequest(callback)generateCall,且最后还执行了execute - call.execute()

总结一下这个开源

  • OkHttpUtils.get().url(url).build()得到了RequestCall,Builder模式呈现
  • 化繁为简,网络请求不需要自己再封装就能够方便的使用
    • 设置下url,就有了OkHttp的Client,request,call和一系繁锁设置,直接调用execute()
    • execute(Callback callback)方法会回调到OkHttpUtils,用主线程Handler更新请求
    • 将OkHttpClient放进了OkHttpUtils;将Request转变成GetRequest;将Request.Builder替换成GetBuilder;将Call替换成RequestCall
文章作者: 二十I邊界
文章链接: https://xuie0000.com/post/2016-01-25-2019/设计模式之Builder模式.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 二十I邊界