• 设计模式之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
    class {
    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
    {
    public RequestCall build()
    {
    if (params != null)
    {
    url = appendParams(url, params);
    }
    return new GetRequest(url, tag, params, headers).build();
    }
    // ...
    public GetBuilder url(String url)
    {
    大专栏  设计模式之Builder模式class="line"> 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);
    }
    // ...
    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
  • 相关阅读:
    请求返回结果模板
    Oracle的sql语句中case关键字的用法 & 单双引号的使用
    java如何从方法返回多个值
    junit的简单用法
    java命令启动jar包
    Fastjson-fastjson中$ref对象重复引用问题
    指定cmd窗口或tomcat运行窗口的名称
    Spring boot配置log4j输出日志
    The import XXX cannot be resolved
    斐波那契数列
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12268273.html
Copyright © 2020-2023  润新知