設計模式之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

/** "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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章