设计模式之工厂方法模式

工厂方法模式,顾名思义,调用工厂里的方法的模式。

一、定义

定义一个用于创建对象的接口,让子类决定实例化哪个类。主要用于生成复杂对象的地方。

二、UML类图
7911186-e42d373d17fc995d.png
工厂模式类图.png
三、解读类图

1.抽象产品类--类图上的Product接口

public abstract class Product {
    public abstract void product(); 
}

2.具体的产品类-类图上的ConcreteProduct

public class ConcreteProduct extends Product{
    @Override
    public void product() {
        System.out.println("生产出一个产品");
    }
}

3.抽象的工厂类-类图上的Factory接口

public abstract class Factory {
    public abstract Product create();
}

4.具体的工厂类-类图上的ConcreteFactory

public class ConcreteFactory extends Factory{
    @Override
    public Product create() {
        return new ConcreteProduct();
    }
}

5.使用工厂类生产产品

public class Client {

    public static void main(String[] args) {
        Factory factory=new ConcreteFactory();
        Product p=factory.create();
        p.product();
    }
}

输出结果:

生产出一个产品

以上是基本的使用方法。在你需要生产对象的时候可以直接使用具体工厂类的create方法产出你要的对象。在Client代码中是看不到具体的产品类ConcreteProduct,因为我们不需要知道内部的实现细节,不需要知道是怎么生产,这就是使用接口(抽象类)的好处,只需要调用暴露的接口方法就行了。

与此同时代码的可拓展性也变强了。比如我想生产另外的对象,那么只需要换一个工厂就行了。

比如换成2号工厂

Factory factory=new ConcreteFactory2(); 

2号工厂用于生产2号产品

public class ConcreteFactory2 extends Factory{
    @Override
    public Product create() {
        return new ConcreteProduct2();
    }
}
public class ConcreteProduct2 extends Product{
    @Override
    public void product() {
        System.out.println("生产出一个2号产品");
    }
}
四、实现工厂方法的第二种方式

有一种方式也比较常用,使用反射的方式去获取产品的对象

1.定义一个工厂抽象类

public abstract class ReflectFactory {
    public abstract<T extends Product> T createProduct(Class<T> clz);
}

2.具体工厂类

public class ReflectConcreteFactory extends ReflectFactory{

    @Override
    public <T extends Product> T createProduct(Class<T> clz) {
        Product p=null;
        try {
            p=(Product) Class.forName(clz.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) p;
    }
}

3.使用工厂类生产

public class ReflectClient {
    public static void main(String[] args) {
        ReflectFactory factory=new ReflectConcreteFactory();
        Product p=factory.createProduct(ConcreteProduct.class);
        p.product();
    }
}

这种方法和基本使用方法不同的是我在使用工厂生产对象的时候,要传入我想生产的那个具体的对象的类。表面看上去还不如之前的方法好,代码变复杂。

但是这有个好处。只要这个具体产品是Product的子类,这些产品都可通过这一个工厂去实现。而之前的方式只能一个工厂对应一个具体的产品。

简单的举个栗子:基本方法就是-可口可乐只能生产可乐,要生产芬达的饮料要芬达工厂去生产。反射的方法-可口可乐和芬达都是刺激性饮料,现在有个工厂专门生产刺激性饮料,但是你要什么可乐还是芬达饮料,你要先和工厂说,它会根据你的要求给你(也就对应传入的参数)

总的来说,两种方式各有所长,在合适的时候选择合适的,才是最好的。

五、Retrofit源码上工厂方法的应用

1.RequestFactory

(1)调用RequestFactory的create方法生产Request的对象。这个Request就是封装了网络请求信息的对象

class RequestFactory {
  okhttp3.Request create(Object[] args) throws IOException {
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
        headers, contentType, hasBody, isFormEncoded, isMultipart);

    List<Object> argumentList = new ArrayList<>(argumentCount);
    for (int p = 0; p < argumentCount; p++) {
      argumentList.add(args[p]);
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.get()  //建造者模式得到Request的对象
        .tag(Invocation.class, new Invocation(method, argumentList))
        .build();
  }
}

(2)在OkHttpCall中调用这个工厂生产对象

  private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

2.Converter.Factory

在创建retrofit对象的时候,经常会添加了一个转换工厂,比如下面代码添加的GsonConverterFactory,是用于把数据转换成gson数据类型

  Retrofit retrofit=new Retrofit.Builder()
                .baseUrl("http://api.github.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

那么它是怎么使用工厂方法模式的呢?

(1)抽象工厂类

public interface Converter<F, T> {
    T convert(F value) throws IOException;
    public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
        Annotation[] annotations, Retrofit retrofit) {
      return null;
    }、
     public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
        Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
      return null;
    }
}

(2)具体的工厂类

public final class GsonConverterFactory extends Converter.Factory {
  public static GsonConverterFactory create() {
    return create(new Gson());
  }
    
  public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson);
  }
  
  //将响应体类型数据转换成?类型数据
  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }

  //将?类型的数据转换成请求体类型的数据
  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
    Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }
}

咋一看看不出它生产的是什么对象。其实在重写的两个方法里,它通过不同的方法生产不同的对象,深入其中的一个requestBodyConverter方法去看

class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
    //...
    public RequestBody convert(T value) throws IOException {
    Buffer buffer = new Buffer();
    Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
    JsonWriter jsonWriter = gson.newJsonWriter(writer);
    adapter.write(jsonWriter, value);
    jsonWriter.close();
    return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
  }
}

最后一行可以看到它返回了一个RequestBody的对象。这也符合了它的目的,就是将现有的类型的数据转换成请求体RequestBody类型的数据。

六、总结

总说看源码不能过于拘泥于细节实现,否则会看得满脸懵逼。但当你真正看的时候,特别是对应初学者,很难区分什么是细节实现,我刚在看Retrofit这部分源码的时候,看到这部分代码,emmn......这到底在干啥。最后我发现原因就是作者使用了大量的设计模式,在你不懂这些设计模式的时候,可不就是看天书一样。但当我去了解一些常用的设计模式基本实现之后,在去看这些代码,莫名其妙的就知道哪些是我不用关心的,比如上面的大多数代码,就为了创建一个对象,我只需要知道创建的对象是什么就行了。

额外说一点

Retrofit是一个很优秀的源码框架。里面用了很多设计模式,很适合花时间去学习。既可以学到Retrofit的源码实现,又能学到多种设计模式,想想就血赚啊~~

当然之后也会有在Retrofit上使用的其他设计模式的文章。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值