基于java-design-patterns白话图解设计模式(个人理解)

Principle 设计原则

Generic

KISS

KISS (Keep It Simple Stupid) 越简单越好

Do The Simplest Thing That Could Possibly Work

Ask yourself: “What is the simplest thing that could possibly work?”

YAGNI

You Ain’t Gonna Need It (翻译:你可能不需要他,即不要过度设计,为了迎合某些产生概率极低的需求而设计的成本是非常高的软件)

YAGNI stands for “you aren’t gonna need it”: don’t implement something until it is necessary.

DRY - Don’t Repeat Yourself

使其每一个部件都是职责明确的并且可重用的

SoC

Separation of concerns

Break program functionality into separate modules that overlap as little as possible.

https://en.wikipedia.org/wiki/Separation_of_concerns

separation of concerns (SoC) is a design principle for separating a computer program into distinct sections such that each section addresses a separate concern. A concern is a set of information that affects the code of a computer program.

SOLID (面向对象设计原则)

一 、单一职责原则 Single Responsibility Principle

  1. 单一原则使类功能更明确,清晰,进而提高代码逻辑,降低代码修改的几率

二、开闭原则 Open Closed Principle

即软件实体如类、模块函数应该对扩展开发,对修改关闭

  • 梅耶开闭原则
    一个类的实现只应该因错误而修改,新的或者改变的特性应该通过新建不同的类实现。新建的类可以通过继承的方式来重用原类的代码。衍生的子类可以或不可以拥有和原类相同的接口。

理解:一个设计好的类错误才去修改【闭】,新功能新建类,扩展功能继承类实现【开】

  • 多态开闭原则
    多态开闭原则的定义倡导由于抽象化接口的使用,在这中间实现可以被改变,多种实现可以被创建,并且多态化的替换不同的实现。

理解:把类可能被修改的方法,抽象化接口化,即把确定性高的属性方法自己实现【闭】,其他的留给接口实现【开】

三、里氏替换原则 Liskov Substitution Principle

派生类(子类)对象可以在程式中代替其基类(超类)对象

理解:

  • 在程序中子类替换父整体的功能不收影响,注意:子类可以重写父类方法但是所实现的内容结果必须大体一致
  • 子类设计时应更关注扩展功能,而不是重写超类方法
  • 父类重写过多应考虑把重写的方法抽象化接口化

四、依赖倒置原则 Dependence Inversion Principle

程序要依赖于抽象接口,不要依赖于具体实现。即面向接口编程

理解:Java语言设计接口和对象的定位决定,开发中尽量使用面向接口编程,或者抽象项目实现面向接口编程

五、迪米特法则 Law of Demeter

最少知识原则(The Least Knowledge Principle),一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话。英文简写为: LOD。

理解:

  1. 用于降低类之间的耦合,使得系统的功能模块功能独立
  2. 【缺点】两个类需要建议依赖关系时,必须通过第三方友元类来传达。
  3. 【类比】我们生活在这个社会,每个人都是相互独立的个体,当需要产生关联时一般的通过第三方,找房子,买房子,找对象,找工作都需要通过第三方,因为每个人时间知识资源有限,一般情况产生连接需要巨大的成本,孤独才是生活的本质。
  4. 应用的例子 门面模式Facade)和中介模式(Mediator)

六、接口隔离原则

使用多个专门的接口比使用单一的总接口要好
百度案例解决:

​ “不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。”这个说得很明白了,再通俗点说,不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。

理解:

合理更加实情把一个接口分为多个接口,让实现类分别实现

引用

Patterns 设计模式

Abstract Document (抽象文档模式)

白话:用同一个接口定义整体和局部,局部细节就可以无限拆分

故事:买车

我想买一辆车,首先要知道它的品牌型号如:300SL,价格 16W

但是我最近狗屎运特别好,厕所捡到了10W块,当然买高配版,轮胎型号15C,价格100¥,车门型号 Lambo 价格300¥,最终用抽象文档模式代码表示,我买到的车:

App.java

public App() {
    LOGGER.info("Constructing parts and car");

    var wheelProperties = Map.of(
        Property.TYPE.toString(), "wheel",
        Property.MODEL.toString(), "15C",
        Property.PRICE.toString(), 100L);

    var doorProperties = Map.of(
        Property.TYPE.toString(), "door",
        Property.MODEL.toString(), "Lambo",
        Property.PRICE.toString(), 300L);

    var carProperties = Map.of(
        Property.MODEL.toString(), "300SL",
        Property.PRICE.toString(), 160400L,
        Property.PARTS.toString(), List.of(wheelProperties, doorProperties));

    var car = new Car(carProperties);

    LOGGER.info("Here is our car:");
    LOGGER.info("-> model: {}", car.getModel().orElseThrow());
    LOGGER.info("-> price: {}", car.getPrice().orElseThrow());
    LOGGER.info("-> parts: ");
    car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}",
        p.getType().orElse(null),
        p.getModel().orElse(null),
        p.getPrice().orElse(null))
    );
  }

配一个网上找的类图

点评

主要的优点是找到总体和局部共有的属性,通过简单的几个属性能详细描绘复杂的总体和部分。

适用性

  • 需要动态添加新属性
  • 你想要一种灵活的方式来组织树状结构中的域 后台常用的配置文件
  • 你想要更松散耦合的系统

Factory Method (工厂方法模式)

白话: 铁匠制作武器,抽象出铁匠技能和武器,不同的铁匠制作出品质不同的武器

我给钱让铁匠做一把剑

铁匠和剑是抽象需要实现

我沟通让铁匠制作不通的武器(Factory)

使用步骤:

步骤1: 创建抽象工厂类,定义具体工厂的公共接口;
步骤2: 创建抽象产品类 ,定义具体产品的公共接口;
步骤3: 创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
步骤4:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例

【工厂】&& 【产品】都抽象出来

Abstract Factory (抽象工厂模式)

白话: 抽象工厂创建,抽象产品,用抽象的工厂创建定义好的接口产品,为后续扩展提供条件

故事:“从0到100万”——中国鞋都莆田口罩生产攻坚记

说实话我听到这个故事还是震惊的,😵 我印象中的“莆田”不是这个样子的呀?应该是莆田系博爱男科,或者是莆田系博士男科啥的。想不到竟然是鞋都,虽然是“Costplay”正版。

好进入正题,莆田通过抽象工厂模式 从鞋子->(转换)口罩工厂 就是典型的抽象工厂模式,代码上就是

莆田 class{

  public FactoryImp factory(String type){
    switch(type){
      case 鞋子:
            return 鞋子_factory;
      case 口罩:
            return 口罩_factory;
    }
  }
}

其实本质是由于生产鞋子和生产口罩的原料和工艺大体是类似的,通过相对简单的整合原料,机器和生产工艺就能得到生产不同产品的工厂。这种做法好处在于充分利用现有资源的情况下,最高效快速的生产出口罩,解决由于疫情爆发导致的口罩稀缺的情况;java-design-patterns 给的例子是一个城堡的例子不太喜欢,感兴趣的可以去看一下,地址如下:
abstract factory github App.java

点评

抽象工厂模式,通过的输入简单鞋子、口罩命令,并抽象规定这个工厂的产出,而具体复杂的资源整合及类的初始化调用的复杂逻辑流程等等都不需要使用者关心。

应用案例

使用步骤

Acyclic Visitor (非循环访问者模式)

详情使用介绍

白话: 调用抽象,不同能力抽象处理,一个类暴露一个接口,就能实现很多种能力

故事:从小我就有一个开游乐园的爸爸,当有同学来游乐园玩的时候,他会根据同学们的要求,兴趣和胆量分配给他们游乐项目的钥匙,当然有的同学拿到多有的拿到少,还有几个拿到了比较危险的项目;

App.java

  public static void main(String[] args) {
    /*分配到的玩项目的权限或钥匙集合*/
    var conUnix = new ConfigureForUnixVisitor()
    var conDos = new ConfigureForDosVisitor();

    //各种各样的游乐设施
    var zoom = new Zoom();
    var hayes = new Hayes();

    // 开玩
    hayes.accept(conDos); // Hayes modem with Dos configurator
    zoom.accept(conDos); // Zoom modem with Dos configurator
    hayes.accept(conUnix); // Hayes modem with Unix configurator
    zoom.accept(conUnix); // Zoom modem with Unix configurator   
  }

上一波项目类图

点评

非循环访问者模式,很近似于我们用不同的钥匙打开不同的门,而打开不同的门,里面会有不同的资源提供给我们使用。

  1. 钥匙和门的关系比较单一,具有固定属性。
  2. 子门子钥匙可以继承父钥匙和门,实现层级结构的划分。

使用场景

  1. 当你想动态的向现有层次结构添加功能(资源)时,不想做修改或影响整体的层次结构,即增加一个门和钥匙无需对整体修改;
  2. 当存在不同层级结构的资源(类比:门)访问操作时,不用修改层级结构,通过ConfigureXXX类进行管理控制;

参考:非循环访问者模式( Acyclic Visitor)

Adapter (适配器模式)

白话 USB转视频接口/USB转高清视频接口

点评

  • 安卓原生最常用类,常用于数据处理类,处理完数据定义好格式,返回给调用类使用,往往数据(事件)处理类格式一定,而返回的数据需要处理展示千变万化,定义一个adapter抽象类,给数据处理类调用,满足数据处理类最小功能和最少改动的设计原则。

Ambassador(大使模式)

设计意图

Provide a helper service instance on a client and offload common functionality away from a shared resource.

为什么叫大使模式

  • 大使是自己人
  • 大使负责处理非本国(远端)事务
  • 【注意】大使负责处理一下链接稳定和链接时长和成功率的统计和反馈

应用场景

服务大使添加其他功能,如日志记录,延迟检查

本地服务大使,用于与远程服务进行交互:

典型案例

  • 控制对其他对象的访问
  • 实现日志记录
  • 实现断路
  • 卸载远程服务任务
  • 促进网络连接

白话

大使为我们(Client)处理外国(Service)的关系,记录交往信息,分析外国局势,使我们更好的应对外围环境的变化。

本地和远端共同实现一个接口,client调用本地大使,大使调用远端服务

点评

把维护service链接的功能放到大使类中处理,如

  1. 访问控制,维护…
  2. 访问日志记录
  3. 链接维护,短路重连,掉包测试…
  4. 卸载服务
  5. 安全管理

API-Gateway API 网关

白话 本地API统一交给API网关管理,对API进行整合及代理管理

Arrange/Act/Assert (AAA)

单元测试的3部模式

  1. Arrange: Perform the setup and initialization required for the test.
  2. Act: Take action(s) required for the test.
  3. Assert: Verify the outcome(s) of the test.

Demo.java

 @Test
  public void testPlus() {
    //Arrange
    var cash = new Cash(3);
    //Act
    cash.plus(4);
    //Assert
    assertEquals(7, cash.count());
  }

Balking

巨简单清晰的多线程竞争一个资源的设计模式,多个线程访问,只有当前资源可以开放访问时可以调用

Bytecode

接收和处理定义过的命令,模拟虚拟机的指令机

Business-delegate (业务代表)

代表负责跟客户沟通,我们是提供实际业务给销售代表审核的人

BusinessDelegate.java

public class BusinessDelegate {
    //实际业务提供公司
  private BusinessLookup lookupService;
  //抽象的业务类型
  private BusinessService businessService;
  //指定业务类型
  private ServiceType serviceType;

  public void setLookupService(BusinessLookup businessLookup) {
    this.lookupService = businessLookup;
  }

  public void setServiceType(ServiceType serviceType) {
    this.serviceType = serviceType;
  }

  public void doTask() {
    businessService = lookupService.getBusinessService(serviceType);
    businessService.doProcessing();
  }
}

Bridge(桥接模式)

Real World Example

Consider you have a weapon with different enchantments, and you are supposed to allow mixing different weapons with different enchantments. What would you do? Create multiple copies of each of the weapons for each of the enchantments or would you just create separate enchantment and set it for the weapon as needed? Bridge pattern allows you to do the second.

Programmatic Example

public interface Weapon {
  void wield();
  void swing();
  void unwield();
  Enchantment getEnchantment();
}

public class Sword implements Weapon {

  private final Enchantment enchantment;

  public Sword(Enchantment enchantment) {
    this.enchantment = enchantment;
  }

  @Override
  public void wield() {
    LOGGER.info("The sword is wielded.");
    enchantment.onActivate();
  }

  @Override
  public void swing() {
    LOGGER.info("The sword is swinged.");
    enchantment.apply();
  }

  @Override
  public void unwield() {
    LOGGER.info("The sword is unwielded.");
    enchantment.onDeactivate();
  }

  @Override
  public Enchantment getEnchantment() {
    return enchantment;
  }
}
public interface Enchantment {
  void onActivate();
  void apply();
  void onDeactivate();
}

理解

  • decouple an abstraction from its implementation so that the two can vary independently ,从一个接口解耦一个抽象的概念,使他们相互独立
  • “nested generalizations” 把部分次要或者辅助的功能抽象,由其他类进行扩展,辅助功能改变不影响主类
  • Bridge pattern is about preferring composition over inheritance 桥接更倾向于聚合而不是继承

Collection-pipeline

  1. Java8 Streams Android 24 (N)最小支持
  2. 可以用Rxjava3来实现函数编程;

Chain(责任链模式)

白话

传递命令,师长-> 团长-> 营长-> 连长-> 排长

点评

每个节点都有接受和专递命令的作用,但是每个节点又有其处理权限处理他这个级别的命令

案例

  1. 官方Demo
public abstract class RequestHandler {
  private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
  private final RequestHandler next;

  public RequestHandler(RequestHandler next) {
    this.next = next;
  }

  public void handleRequest(Request req) {
    if (next != null) {
      next.handleRequest(req);
    }
  }

  protected void printHandling(Request req) {
    LOGGER.info("{} handling request \"{}\"", this, req);
  }

  @Override
  public abstract String toString();
}

public class OrcCommander extends RequestHandler {
  public OrcCommander(RequestHandler handler) {
    super(handler);
  }

  @Override
  public void handleRequest(Request req) {
    if (req.getRequestType().equals(RequestType.DEFEND_CASTLE)) {
      printHandling(req);
      req.markHandled();
    } else {
      super.handleRequest(req);
    }
  }

  @Override
  public String toString() {
    return "Orc commander";
  }
} 
  1. OKHttp 通过Intercepter这种连式设计,大大简化了请求访问的功能,并且提供了非常多的可扩展性

  1. Window input事件的转发
    / 事件分发不同阶段的基类
    abstract class InputStage {
    private final InputStage mNext;  // 指向事件分发的下一阶段
    }
    

// InputStage的子类,象征事件分发的各个阶段

final class ViewPreImeInputStage extends InputStage {}

final class EarlyPostImeInputStage extends InputStage {}
//视图输入处理阶段 ,主要处理按键、轨迹球、手指触摸及一般性的运动事件
final class ViewPostImeInputStage extends InputStage {}
//综合性处理阶段 ,主要针对轨迹球、操作杆、导航面板及未捕获的事件使用键盘进行处理:
final class SyntheticInputStage extends InputStage {}

abstract class AsyncInputStage extends InputStage {}

final class NativePreImeInputStage extends AsyncInputStage {}
//输入法事件处理阶段 ,会从事件中过滤出用户输入的字符,如果输入的内容无法被识别,则将输入事件向下一个阶段继续分发
final class ImeInputStage extends AsyncInputStage {}

final class NativePostImeInputStage extends AsyncInputStage {}

//使用
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
“aq:native-post-ime:” + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
“aq:ime:” + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
“aq:native-pre-ime:” + counterSuffix);
mFirstInputStage = nativePreImeStage;

出处:[反思|Android 事件分发机制的设计与实现](https://juejin.cn/post/6844903926446161927)

- [OKHttp源码解析](https://www.jianshu.com/p/27c1554b7fee)



## Caching(缓存策略)

> 为了尽量减少数据获取/刷新的成本,根据数据获取的消耗(网络、内存、文件),根据数据属性选择最符合应用场景的缓存策略

1. 主要类职责
   1. ChacheStore 负责数据增删改查的功能,定义成接口由不同的数据源实现;
   2. CachingPolicy 定义常用应用场景使用的缓存策略,排列获取数据的优先级,更新本地缓存的策略
   3. CacheControl  okhttp3.CacheControl.java 根据[Hypertext Transfer Protocol (HTTP/1.1): Caching](https://tools.ietf.org/html/rfc7234#section-5.2) 根据HTTP Caching协议及根据服务器返回的Caching指令设置缓存模式
   4. CacheManager 负责初始化store,policy,Cachecontrol,协调好内部类向外部提供简单的操作接口



### 阅读记录

- [一日一学_okhttp(本地缓存)](https://www.jianshu.com/p/80766c227bf8)



## Decorator (装饰模式)

> 按照接口的思维理解,非常清楚,即把类的部分固有方法(作用)抽象成接口,交给实现了该抽象接口的类来实现,具体怎么实现看实现类

### 关键点

1. 部分方法抽象
2. 装饰类实现抽象方法的具体内容

## [Dao](https://github.com/iluwatar/java-design-patterns/tree/master/dao) (Data Access Object,数据访问对象)

### DAO组成

DatabaseConnection:专门负责数据库打开与关闭操作的类

VO:主要由属性,setter, getter方法组成,VO类中的属性与表中的字段相对应,每一个VO类的对象都表示表中的每一条记录;

DAO:主要定义操作的接口,定义一系列数据库的原子性操作,例如增删改查等;

Impl: DAO接口的真实实现类,主要完成具体数据库操作,但不负责数据库的打开和关闭;

Proxy:代理实现类,主要完成数据库的打开和关闭并且调用真实实现类对象的操作;

Factory: 工厂类,通过工厂类取得一个DAO的实例化对象。



### 对于包的命名:

- 数据库连接: xxx.dbc.DatabaseConnection
- DAO接口: xxx.dao.IXxxDAO
- DAO接口真实实现类:xxx.dao.impl.XxxDAOImpl
- DAO接口代理实现类:xxx.dao.proxy.XxxDAOProxy
- VO类: xxx.vo.Xxx, VO命名要与表的命名一致
- 工厂类:xxx.factory.DAOFactory.

参考:[DAO设计模式简介](https://blog.csdn.net/thystar/article/details/41786763)

##  Facade (外观或门面模式)

> Facade pattern provides a simplified interface to a complex subsystem.

直接上java-design-patterns 案例

`金矿挖矿工作`

1. 把不同矿工进行抽象

   ```java
   public abstract class DwarvenMineWorker {

     private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenMineWorker.class);

     public void goToSleep() {
       LOGGER.info("{} goes to sleep.", name());
     }

     public void wakeUp() {
       LOGGER.info("{} wakes up.", name());
     }

     public void goHome() {
       LOGGER.info("{} goes home.", name());
     }

     public void goToMine() {
       LOGGER.info("{} goes to the mine.", name());
     }

     private void action(Action action) {
       switch (action) {
         case GO_TO_SLEEP:
           goToSleep();
           break;
         case WAKE_UP:
           wakeUp();
           break;
         case GO_HOME:
           goHome();
           break;
         case GO_TO_MINE:
           goToMine();
           break;
         case WORK:
           work();
           break;
         default:
           LOGGER.info("Undefined action");
           break;
       }
     }

     public void action(Action... actions) {
       Arrays.stream(actions).forEach(this::action);
     }

     public abstract void work();

     public abstract String name();

     enum Action {
       GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK
     }
   }
  1. 具体实现工工种

    public class DwarvenTunnelDigger extends DwarvenMineWorker {
    
      private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenTunnelDigger.class);
    
      @Override
      public void work() {
        LOGGER.info("{} creates another promising tunnel.", name());
      }
    
      @Override
      public String name() {
        return "Dwarven tunnel digger";
      }
    }
    
    public class DwarvenGoldDigger extends DwarvenMineWorker {
    
      private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenGoldDigger.class);
    
      @Override
      public void work() {
        LOGGER.info("{} digs for gold.", name());
      }
    
      @Override
      public String name() {
        return "Dwarf gold digger";
      }
    }
    
    public class DwarvenCartOperator extends DwarvenMineWorker {
    
      private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenCartOperator.class);
    
      @Override
      public void work() {
        LOGGER.info("{} moves gold chunks out of the mine.", name());
      }
    
      @Override
      public String name() {
        return "Dwarf cart operator";
      }
    }
  2. 暴露出整个系统需要暴露的内容

    public class DwarvenGoldmineFacade {
    
      private final List<DwarvenMineWorker> workers;
    
      public DwarvenGoldmineFacade() {
          workers = List.of(
                new DwarvenGoldDigger(),
                new DwarvenCartOperator(),
                new DwarvenTunnelDigger());
      }
    
      public void startNewDay() {
        makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE);
      }
    
      public void digOutGold() {
        makeActions(workers, DwarvenMineWorker.Action.WORK);
      }
    
      public void endDay() {
        makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP);
      }
    
      private static void makeActions(Collection<DwarvenMineWorker> workers,
          DwarvenMineWorker.Action... actions) {
        workers.forEach(worker -> worker.action(actions));
      }
    }
  3. 调用

    var facade = new DwarvenGoldmineFacade();
    facade.startNewDay();
    facade.digOutGold();
    facade.endDay();

理解

  • 复杂的子系统提供最简单的接口(provides a simplified interface to a complex subsystem)

Mediator (中介者模式)

Define an object that encapsulates how a set of objects interact.

java-pattern案例类图

我的理解

Template Method (模板方法模式)

这个很常用也很好理解,及父类定义好几个抽象方法给子类实现

优点

  1. 父类实现了该类几乎所有方法,留下几个变动的抽象方法给子类实现,减少代码量提高效率【重点】
  2. 规矩规矩,有规矩之后代码就有清晰的逻辑,易于后期维护【重点】

Active-object

  • 把异步的执行的方法放到父类实现,所有子类都能轻松用触发异步方法
  • LinkedBlockingQueue
    • 链表结构
    • Blocking 使用ReentrantLock takeLock,putLock 不满足条件堵塞当条件满足时放开

Async-method-invocation

Circuit-breaker (中断回路)

用于接口调用状态记录中断回路处理

中断处理属性有

  1. Timeout 超时时间
  2. retryTimePeriod 重试间隔
  3. failureCount 失败次数
  4. failureThreshold 最大失败次数
  5. lastFailureTime 上次失败时间

点评

  • 整个把中断请求/调用处理放到一个类里维护对于链接有强稳定性的程序是很好的,因为链接(访问)稳定性要求高的基本是优化中断回路这个逻辑
  • 对于一般调用使用上有过度设计的问题
  • 这个模式设计得不够精巧,达不到实用级别
  • 整个中断回路使用RxJava这种函数编程有天然语法优势,对中断回路更简明

源码阅读

1. Retrofit 2.0

参考:

感悟:

  1. 看源码

    1. 首先要清楚源码的大体框架走向在看,如retrofit就是请求和返回处理;

    2. 根据代码使用方法,一层层的分析源码,逻辑清晰

    3. 看源码能发现源码一些自己不知道使用方法,通过设置缓存强制使用responses

      Request request = new Request.Builder()
           .cacheControl(new CacheControl.Builder()
           .maxStale(365, TimeUnit.DAYS)
           .build())
          .url("http://publicobject.com/helloworld.txt")
          .build();
  1. 代码设计由大自小理清功能和属性把它们定义到类中,即程序设计来源于生活,

    1. 先定义好类,如家,家的属性,家的作用,家里面又有家具,家电它们也有相应的属性和作用。
    2. 然后通过设计模式来设计可扩展,方便维护的关系结构。
  2. 设计方法

    1. builder,提供一个builder类初始化类,在不配置的情况下提供一些默认操作,极大简化类的初始化过程;

    2. chain, okhttp3.Call.Factory, Converter.Factory 通过nextCallAdapter遍历,抽象接口List逐步调用,极大的提高程序扩展性

        public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
            Annotation[] annotations) {
      
          int start = callAdapterFactories.indexOf(skipPast) + 1;
          for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
            CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
            if (adapter != null) {
              return adapter;
            }
          }
        }

2. OKHttpClient

附录

java-design-patterns

设计模式的分类