在Java中我们通常把接口作为系统与外界交互的窗口,接下来我们来考虑以下问题:
- 如何设计接口?
- 当两个系统之间接口不匹配时,如何处理?
- 但系统A无法便捷的引用系统B的接口的实现类实例时,如何处理?
- ……
为了解决以上问题,需要引入与接口相关的设计模式,接下来介绍定制服务模式、适配器模式、默认适配器模式、代理模式、标识类型模式和常量接口模式。
- 定制服务模式
在如今的商业领域,很流行定制服务。例如电信公司会制定各种各样的服务套餐,满足各种客户的需求。下表是电信公司为个人用户定制的两款宽带服务套餐:
极速精英套餐 | 金融专网套餐 |
---|---|
宽带上网服务(限速2Mbps) | 电信金融专网服务(限速1Mbps) |
在线杀毒服务 | 在线杀毒服务 |
50MB邮箱服务 | 28MB网络硬盘服务 |
5MB邮箱服务 | |
价格:140元无限包月 | 价格:150元无限包月 |
当一个系统能对外提供多种类型的服务时,一种方式是设计粗粒度的接口,把所有的服务放在一个接口中声明,这个接口臃肿庞大,所有的使用者都访问同一个接口;还有一种方式是设计精粒度的接口,对服务精心分类,针对使用者的需求提供特定的接口。
显然第二种精粒度的接口方式会让系统更加容易维护,精粒度的接口可以减轻软件提供商软件维护成本。假如某个精粒度的接口不得不发生变更,那么也只会影响到一小部分访问该接口使用者。此外,精粒度的接口更有利于接口的重用,通过对接口的继承,可以方便的生成针对特定使用者的复合接口。
在上述例子中,可以抽象出5个精粒度的接口,代表5种服务,这5种服务分别是:
- 宽带上网服务 BroadbandService
- 网络硬盘服务 NetworkDiskService
- 在线杀毒服务 VirusKillingService
- 邮箱服务 MailboxService
- 金融专网服务 FinancialNetworkService
上表中的极速精英套餐SuperSpeedCombo和金融专网套餐FinanceCombo属于两种定制的服务接口,它们可以通过继承以上5个精粒度的接口而形成,这样的接口也称为复合接口。
服务接口定制好以后,接下来的问题是如何实现这些接口。为了提高代码的可重用性,类的粒度也应该尽可能小,所以首先为精粒度的接口提供实现类。
以下列出其中的一个服务实现类:
public class BroadbandServiceImpl implements BroadbandService{
private int speed;//网速
public BroadbandServiceImpl(int speed){
this.speed = speed;
}
//连接网络
public void connect(String username,String password){...}
//断开网络
public void disconnect(){...}
}
同上,将精粒度的接口一一创建实现类,得到精粒度的类。
那么对于SuperSpeedCombo 和 FinanceCombo 复合接口,如何实现它们呢?以 SuperSpeedCombo接口的实现类 SuperSpeedComboImpl为例,可以采用组合手段,复用 BroadbandService接口、VirusKillingService接口和MailboxService接口的实现类的程序代码。
那么什么是组合关系呢?在这再复习一下,所谓的组合和继承都是提高代码可重用性的手段,继承最大的弱点就是破坏封装,子类和父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性,而组合关系不会破坏封装,整体类与局部类之间松耦合,彼此相互独立。当然组合关系也有缺点:创建整体类的对象时需要创建所有局部类的对象,而继承关系在创建子类的对象时无须创建父类的对象。
比如要在SuperSpeedComboImpl采用组合手段加入宽带上网服务BroadbandService:
public class SuperSpeedComboImpl implements SuperSpeedCombo{
private BroadbandServiceImpl BroadbandService;