Effective-Java读书笔记2-服务提供者架构

摘要: 通过学习 Effective Java 的第一条规则中学习到了 Service Provider Framework。本文详细的介绍该框架,希望通过本文综合现有的资料,可以一站式的让你理解什么是服务提供者框架

原文参考

静态工厂方法返回的对象所属的类,在编写包含该静态工厂方法的类时可以不必存在。这 种灵活的静态工厂方法构成了服务提供者框架(Service Provider Framework)的基础,例如 JDBC (Java数据库连接,Java Database Connectivity) API。服务提供者框架是指这样一个系 统:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从 多个实现中解耦出来。

服务提供者框架中有三个重要的组件:服务接口(Service Interface),这是提供者实现 的I提供者注册API (Provider Registration API),这是系统用来注册实现,让客户端访问它 们的;服务访问API (Service Access API),是客户端用来获取服务的实例的。服务访问API 一般允许但是不要求客户端指定某种选择提供者的条件。如果没有这样的规定,API就会返回 默认实现的一个实例。服务访问API是“灵活的静态工厂”,它构成了服务提供者框架的基础。

服务提供者框架的第四个组件是可选的:服务提供者接口(Service Provider Interface),这 些提供者负责创建其服务实现的实例。如果没有服务提供者接口,实现就按照类名称注册,并 通过反射方式进行实例化(见第53条)。对于JDBC来说,Connection就是它的服务接口, DriverManager.registerDriver是提供者注册API,DriverManager.get Connection是服务访问API, Driver就是服务提供者接口。

服务提供者框架模式有着无数种变体。例如,服务访问API可以利用适配器(Adapter) 模式[Gamma95,p.139],返回比择供者需要的更丰富的服务接口。下面是一个简单的实现, 包含一个服务提供者接口和一个默认提供者:

概述

我们如何理解这句话:“多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来”?这里有几个元素

  1. 服务 Service
  2. 服务提供者 Service Provider
  3. 系统 应该指代该框架的管理器
  4. (服务提供者的)客户端 Client
  5. 实现 服务接口的具体实现

我们用 JDBC 来举例子, JDBCsql.Connection 就是服务,这个服务接口仅定义了功能函数名,而没有实现,而服务提供者需要自行实现这些功能接口。比如 Mysql 就实现了 sql.ConnectiongetSchema() 方法,其中的客户端一般只某个服务提供者的客户端,比如你的项目使用了 Mysql,那么你的项目就是 Mysql 的客户端。该客户端需要使用 Mysql 提供的服务的实现。而这个框架就是用于解耦客户端服务提供者的服务实现

通俗一点就是客户端不需要直接依赖服务提供者的服务实现,而是使用这样一个框架来访问其服务实现,如果有其他服务提供者也遵循同一个框架,那么客户端可以很容易的切换到该服务提供商。比如某个项目使用了 Mysql 并且使用 Mysql 提供的 JDBC 服务实现。如果使用该框架,那么如果有一天突然要变更到 Oracle,只需要更改为 OracleJDBC 服务实现,大部分的代码都不需要更改(除了少部分服务提供者特有的特性依赖除外)就可以顺利完成变更。

类图分析

通过该类图我们可以发现,我们实际上在这个框架中有三个角色,一个是服务接口抽象层的标准定制者,一个是服务具体实现的提供商,最后一个是使用服务的客户端。在 Effective-Java 2rd (以后称为 EJ2) 一书中并没有提到客户端,但是我个人理解只有加上这个角色才能更好的理解这个框架,因为大多数人都曾经扮演过客户端这个角色。

通过该类图我们可以发现,其中客户端和具体的服务提供者之间没有直接依赖,也就意味着客户端可以比较容易切换不同的服务提供者。同时服务提供者也可以在方便的开发具体的服务。也就是在顶层抽象的基础上开发和使用进行了解耦。

应用场景分析

什么情况下会使用这种框架呢?java 的 JDBC 是一个最好的例子,我们前面也一直用这个来距离,其他博文也提出了一些模拟的项目,比如公交卡项目

概括的讲,如果某个功能有多种实现方法,而且客户端在使用的时候是有一定可能存在更换,那么这个框架就是否有用。

另外其注册和访问的理念也可以单独抽象出来使用,比如我们需要连接某个服务器,但是我们需要控制连接数量或者尽可能复用连接。那么就可以把这个框架中的 providers 换成 connection, 而服务就是连接。我们可以注册连接,然后需要使用连接的时候,直接获取,我们可以注册多个连接构成连接池,还可能在获取连接(也就是 Service access)的时候使用一定的策略,比如负载均衡等。