设计原则之依赖倒置和接口隔离
软件设计常见的五大设计原则有:开闭原则、依赖倒置原则、里氏替换原则、单一职责原则、接口隔离原则。本文主要谈谈依赖倒置原则和接口隔离原则。
依赖倒置原则
定义
依赖倒置是指系统分层设计中接口所有权的倒置。
早期引入分层设计,是为了建立清晰的软件分层关系,便于高层模块依赖低层模块,但这样存在一些缺点:一来维护困难,低层实现变动可能会影响到高层模块;二来复用困难,通常来说,越是高层模块,复用价值越大,但由于高层模块依赖低层模块,对高层模块的依赖会级联依赖低层模块,使复用变得困难。
因此需要通过依赖倒置原则实现低耦合、易复用的需求。
依赖倒置原则需遵循以下规范:
高层模块不应该依赖低层模块,二者都应该依赖抽象。
抽象不应该依赖具体实现,具体实现应该依赖抽象。
简单来说就是:高层模块定义所需服务接口,由低层模块来实现该接口。
又称“好莱坞原则”
依赖倒置原则又常被称为“好莱坞原则”。“好莱坞原则”的理念就是:Don't call me,I will call you。从开发角度看就是:不要调我,我会调你。这个原则在我们日常开发使用的各种框架中非常常见,如spring、tomcat等,我们业务代码都不需要调用这些框架的方法便可以使用这些框架提供的服务来完成我们的业务需求,如处理Http请求。
几个例子
依赖倒置原则存在于诸多场景中:
linux操作系统通过定义VFS抽象由底层具体的文件系统开发商来共同依赖,进而屏蔽各种文件系统的差异;
再比如web容器,如tomcat、jetty等,基于J2EE规范,开发人员只要开发符合Servlet规范的类,便可方便地处理用户请求,从而为我们屏蔽掉底层复杂的通信细节;
再比如Spring AOP切面编程,通过切面抽象,我们可以轻易实现非侵入性逻辑增强,比如日志记录、事务处理等;
JDBC抽象,为应用程序屏蔽底层数据库驱动的差异,等等。
具体来看看Spring AOP的实现原理:
从图中,我们可以看到几个抽象:
Aspect:通常叫做方面,是对完整切面逻辑的表达(在spring中也称为Advisor),其包括:PointCut和Advice。
PointCut:定义了切面编程Where的问题,即在哪里进行逻辑增强,可以通过具体类名和方法名实现,也可以通过正则表示式来定义,它可能会对应多个Join Point。
Join Point:可以切入的特定点,在Spring中,只有方法可以作为Join Point。
Advice:定义了切面编程What和When的问题,即在什么时候做什么。
简单来说,一个Aspect就是定义在特定时间和地点做什么的抽象,通过这样的抽象,开发人员可以方便对业务代码进行逻辑增强,同时保证了代码的可维护性。
接口隔离原则
定义
接口隔离原则是说:不应该强迫用户依赖他们不需要的方法。
原因
用户看到不需要的方法,会增加使用难度,甚至错误使用会导致bug产生;
带来不必要的耦合。当这些方法需要变动时,不需要但依赖这些方法的用户程序也需要调整。
当一个类中的多个方法之间是互相关联,无法拆分成多个类的情况下,运用接口隔离原则,可将不同调用者的关注点(方法)隔离开来。
问题
请用接口隔离原则优化 Cache 类的设计,画出优化后的类图。
解读
cache 实现类中有四个方法,其中put、get、delete方法是需要暴露给应用程序的,rebuild方法是需要暴露给系统进行远程调用的。如果将rebuild暴露给应用程序,应用程序可能会错误调用 rebuild 方法,导致 cache 服务失效。
按照接口隔离原则:不应该强迫客户程序依赖它们不需要的方法。也就是说,应该使 cache 类实现两个接口,一个接口包含put、get、delete暴露给应用程序,一个接口包含rebuild暴露给系统远程调用。从而实现接口隔离,使应用程序看不到 rebuild 方法。
优化后的类图如下:
总结
软件系统设计的一个重要目标是“高内聚,低耦合”,依赖倒置原则和接口隔离原则其实也是在往这个目标靠拢。依赖倒置原则通过依赖抽象而非具体实现,而且是由高层模块来定义抽象,这就实现了高层模块和底层模块的解耦合,保证了高层模块的稳定与可复用性。而接口隔离原则通过为不同调用者实现不同接口,从而实现调用者关注点分离,省去了调用者对不需要方法的依赖带来的耦合。
版权声明: 本文为 InfoQ 作者【林昱榕】的原创文章。
原文链接:【http://xie.infoq.cn/article/f1e76ad26dafd6c7b0c671c49】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论 (1 条评论)