Android 设计模式Android开发Android开发经验谈

设计模式之建造者模式

2017-10-20  本文已影响41人  C_zx

模式定义

建造者模式:将一个复杂产品的创建与表示分离,使得同样的创建过程可以创建不同的表示
客户端不用去关心产品对象的内部组成,只需要关注如何一步一步的去创建复杂对象,建造者模式是一种创建型模式,何为创建型模式? 顾名思义就是创建对象的设计模式,如常用的单例模式,工厂模式等都为创建型模式。

模式结构

建造者模式主要有以下四个角色:

Builder.jpg

代码分析

Product:具体创建的产品对象

public class Product {

    private String partA;
    private String partB;
    private String partC;
    
    public String getPartA() {
        return partA;
    }
    public void setPartA(String partA) {
        this.partA = partA;
    }
    public String getPartB() {
        return partB;
    }
    public void setPartB(String partB) {
        this.partB = partB;
    }
    public String getPartC() {
        return partC;
    }
    public void setPartC(String partC) {
        this.partC = partC;
    }
    
    
}

Builder:抽象建造者

public abstract class Builder {
    public Product product = new Product();
    public abstract void buildPartA();
    public abstract void buildPartB();
    public abstract void buildPartC();
    public Product getResult() {
        return product;
    }

}

ConcreteBuilder:具体建造者


public class ConcreteBuilder extends Builder{
    

    @Override
    public void buildPartA() {
        // TODO Auto-generated method stub
        product.setPartA("partA");
        
    }

    @Override
    public void buildPartB() {
        // TODO Auto-generated method stub
        product.setPartB("partB");
        
    }

    @Override
    public void buildPartC() {
        // TODO Auto-generated method stub
        product.setPartC("partC");
        
    }

}

Director:指挥者

public class Director {

    private Builder builder;
    public Director(Builder builder) {
        this.builder = builder;
        
    }
    public Product construct() {
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
        return builder.getResult();
    }

}

测试及结果:

public class Test {
    public static void main(String[] args) {
        
        ConcreteBuilder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        Product product = director.construct();
        System.out.println(product.getPartA());
        System.out.println(product.getPartB());
        System.out.println(product.getPartC());
        
    }
    

}

从测试代码来看,客户端只需要知道具体的创建者类型,并通过指挥者就可以创建想要的对象,无需关系产品内部的具体构造细节,Builder抽象定义了产品的创建方法和返回方法,而真正的实现是ConcreteBuilder,我们也可以定义不同的ConcreteBuilder,可以定义多个ConcreteBuilder。对于客户端而言,Director分离了产品的创建过程,通过调用建造者的一系列方法返回一个完整的产品对象,这样就做到了所谓的创建与表示相分离,且同样的创建过程有不同的表示。在我们日常的使用中,如果只有一个具体的建造者,通常会省略掉具体的建造者和指挥者,Builder自身充当指挥者角色,下面我们通过分析时下比较流行的网络框架Retrofit的创建过程,它就是采用Builder模式来创建对象。PS:很多不错的开源框架都用到了Builder设计模式

实例分析

接下来首先看一下retrofit对象创建的代码

 Retrofit retrofit = new Retrofit.Builder()
                            .baseUrl("http:www.baidu.com")
                            .addConverterFactory(ScalarsConverterFactory.create())
                            .addConverterFactory(GsonConverterFactory.create())
                            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                            .build();

retrofit对象创建采用了建造者模式,只不过它省略了ConcreteBuilder和Director这俩个角色,我们来看一下它的源码,这里并不是Retrofit这个类的所有源代码,我删除了一些跟本文内容无关的代码


public final class Retrofit {
  

  final okhttp3.Call.Factory callFactory;
  final HttpUrl baseUrl;
  final List<Converter.Factory> converterFactories;
  final List<CallAdapter.Factory> adapterFactories;
  final Executor callbackExecutor;
  final boolean validateEagerly;

  Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
      List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
      Executor callbackExecutor, boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
    this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }


  public okhttp3.Call.Factory callFactory() {
    return callFactory;
  }

  /** The API base URL. */
  public HttpUrl baseUrl() {
    return baseUrl;
  }

  public List<CallAdapter.Factory> callAdapterFactories() {
    return adapterFactories;
  }


  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }


  public List<Converter.Factory> converterFactories() {
    return converterFactories;
  }
  
  public Executor callbackExecutor() {
    return callbackExecutor;
  }

  public Builder newBuilder() {
    return new Builder(this);
  }

  
  public static final class Builder {
    private final Platform platform;
    private okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
    private Executor callbackExecutor;
    private boolean validateEagerly;

    Builder(Platform platform) {
      this.platform = platform;
      converterFactories.add(new BuiltInConverters());
    }

    public Builder() {
      this(Platform.get());
    }

    Builder(Retrofit retrofit) {
      platform = Platform.get();
      callFactory = retrofit.callFactory;
      baseUrl = retrofit.baseUrl;
      converterFactories.addAll(retrofit.converterFactories);
      adapterFactories.addAll(retrofit.adapterFactories);
      // Remove the default, platform-aware call adapter added by build().
      adapterFactories.remove(adapterFactories.size() - 1);
      callbackExecutor = retrofit.callbackExecutor;
      validateEagerly = retrofit.validateEagerly;
    }

   
    public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }

    public Builder callFactory(okhttp3.Call.Factory factory) {
      this.callFactory = checkNotNull(factory, "factory == null");
      return this;
    }

   
    public Builder baseUrl(String baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      HttpUrl httpUrl = HttpUrl.parse(baseUrl);
      if (httpUrl == null) {
        throw new IllegalArgumentException("Illegal URL: " + baseUrl);
      }
      return baseUrl(httpUrl);
    }

   
    public Builder baseUrl(HttpUrl baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
    }

   
    public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

   
    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      adapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

   
    public Builder callbackExecutor(Executor executor) {
      this.callbackExecutor = checkNotNull(executor, "executor == null");
      return this;
    }

  
    public Builder validateEagerly(boolean validateEagerly) {
      this.validateEagerly = validateEagerly;
      return this;
    }

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
  }
}

首先我们来分析下源码中的角色,其中有俩个角色,分别为Retrofit类和其静态内部类Builder,结合之前的建造者模式角色分析,这里的Retrofit其实就是我们要创建的产品Product,但是这里的Builder并不是一个抽象类,而且没有发现之前所分析的具体建造者ConcreteBuilder和指挥者Director,正如上面所说,当只有一个具体的建造者时,我们可以省略掉具体建造者这个角色,如果省略掉具体建造者,那么指挥者也可以一并省略,Builder自身充当建造者与指挥者双角色。那Builder是如何充当这俩个角色的呢?在Builder类中有一系列公开方法且返回值都是自身,其实这些方法就是对Retrofit的成员属性进行了实例化和赋值,Builder类中还有一个重要的Build方法,该方法的返回值是我们要创建的对象Retrofit,Build方法中首先对Retrofit的相关成员属性做了判空操作,最后调用了Retrofit的构造方法返回Retrofit对象并完成了对象的创建。

总结

上一篇 下一篇

猜你喜欢

热点阅读