设计模式之Builder模式

来源:互联网 发布:windows ble蓝牙开发 编辑:程序博客网 时间:2024/04/28 07:00

参与者

  • 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

/** "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();    }}

调用

/** 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分析

String url = "http://www.csdn.net/";OkHttpUtils        .get()        .url(url)        .build()        .execute(new MyStringCallback());

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

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

public static GetBuilder get(){    return new GetBuilder();}
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了 - 这、、、

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()没有?继续

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

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
0 0