OkHttp设计模式剖析(四)享元模式

上一篇 OkHttp设计模式剖析(三)策略模式

下一篇 OkHttp设计模式剖析(五)观察者模式

OKHTTP:

由大名鼎鼎的Square公司开发的网络通信库。

设计模式:

软件开发中问题的解决套路。

享元模式简介

定义:使用共享对象可有效地支持大量的细粒度的对象。

享元模式(Flyweight)是对象池的一种实现,可以节约内存,适合可能存在大量重复对象的场景。享元对象中的部分状态可以共享,可以共享的状态为内部状态,不可以共享的状态为外部状态。
许多某某池都使用了享元模式,比如线程池,连接池,数据池,缓存池,消息池等。享元模式会在池中先找,若没有可以复用的对象,才新建一个。

ConnectionPool(连接池)中的享元模式

OkHttp3将客户端与服务器之间的连接定义为接口Connection,通过RealConnection实现,在ConnectionPool中,将连接储存在一个双端队列中。

public final class ConnectionPool {
  // 双端队列储存RealConnection
  private final Deque connections = new ArrayDeque<>();
  // 构造函数
  public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) { ...... }
}

跳转到StreamAllocation类中findConnection函数,源码如下:

private RealConnection findConnection(int connectTimeout, int readTimeout, int writeTimeout, boolean connectionRetryEnabled) throws IOException {
    Route selectedRoute;
    synchronized (connectionPool) {
      if (released) throw new IllegalStateException("released");
      if (codec != null) throw new IllegalStateException("codec != null");
      if (canceled) throw new IOException("Canceled");

      RealConnection allocatedConnection = this.connection;
      if (allocatedConnection != null && !allocatedConnection.noNewStreams) {
        return allocatedConnection;
      }
      // 从连接池中找符合条件的连接,若有则返回
      RealConnection pooledConnection = Internal.instance.get(connectionPool, address, this);
      if (pooledConnection != null) {
        this.connection = pooledConnection;
        return pooledConnection;
      }
      selectedRoute = route;
    }
    if (selectedRoute == null) {
      selectedRoute = routeSelector.next();
      synchronized (connectionPool) {
        route = selectedRoute;
        refusedStreamCount = 0;
      }
    }
    // 连接池中没有,则新建
    RealConnection newConnection = new RealConnection(selectedRoute);
    synchronized (connectionPool) {
      acquire(newConnection);
      Internal.instance.put(connectionPool, newConnection);
      this.connection = newConnection;
      if (canceled) throw new IOException("Canceled");
    }
    newConnection.connect(connectTimeout, readTimeout, writeTimeout, address.connectionSpecs(),
        connectionRetryEnabled);
    routeDatabase().connected(newConnection.route());
    return newConnection;
}

这就是通过享元模式实现连接的复用,从而节省内存。

基于享元模式构建的其他代码

1、OkHttp中的Dispatcher的线程池也用到了享元模式

public final class Dispatcher {
  private int maxRequests = 64;
  private int maxRequestsPerHost = 5;
  private Runnable idleCallback;

  private ExecutorService executorService; //懒加载的无边界限制的线程池

  public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

  public Dispatcher() {
  }

  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }
  
}

通过维护ExecutorService线程池实现复用。
2、Android源码中的消息队列

家用工具箱1-10号螺丝刀

public class Screwdriver {
    private int size;
    public Screwdriver(int size) {
        this.size = size;
    }
    public int getSize() {
        return size;
    }
}

public class TestScrewdriver {

    static HashMap s = new HashMap();
    
    public static void main(String[] args) {
        // 假设螺丝刀只有1-10号
        s.put(1, new Screwdriver(1));
        s.put(2, new Screwdriver(2));
        s.put(5, new Screwdriver(5));
        s.put(10, new Screwdriver(10));
        for(int i=1; i<=10;i++) {
            if(s.containsKey(i)) {
                System.out.println("已经有"+i+"号螺丝刀,不用买了     "+s.get(i));
            }else {
                
                System.out.println("需要购买一把"+i+"号螺丝刀");
            }
        }

    }
}
/*输出结果:
已经有1号螺丝刀,不用买了     Screwdriver@15db9742
已经有2号螺丝刀,不用买了     Screwdriver@6d06d69c
需要购买一把3号螺丝刀
需要购买一把4号螺丝刀
已经有5号螺丝刀,不用买了     Screwdriver@7852e922
需要购买一把6号螺丝刀
需要购买一把7号螺丝刀
需要购买一把8号螺丝刀
需要购买一把9号螺丝刀
已经有10号螺丝刀,不用买了     Screwdriver@4e25154f
*/

所以,享元设计模式的核心就是:池中复用。

参考文献

1、设计模式|菜鸟教程:https://www.runoob.com/design-pattern/design-pattern-tutorial.html
2、《Android源码设计模式解析与实战》何红辉,关爱民著
3、隔壁老李头:https://www.jianshu.com/p/82f74db14a18

上一篇 OkHttp设计模式剖析(三)策略模式

下一篇 OkHttp设计模式剖析(五)观察者模式

All is well.

你可能感兴趣的:(OkHttp设计模式剖析(四)享元模式)