框架设计示例
1. 请描述什么是依赖倒置原则,为什么有时候依赖倒置原则又被称为好莱坞原则?
依赖倒置原则(Dependence Inversion Principle ,DIP)定义如下:
High level modules should not depend upon low level modules,Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstracts.
总结提炼以后为以下三点:
高层模块不应该依赖低层模块,两者都应该依赖抽象
抽象不应该依赖细节
细节应该依赖抽象
也可以说高层模块,低层模块,细节都应该依赖抽象
通过定义可以知道,依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合。采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定,降低并行开发引起的风险,提高代码的可读性和可维护性。
“不要给我们打电话,我们会给你打电话(don‘t call us, we‘ll call you)”这是著名的好莱坞原则 。好莱坞原则强调高层对低层的主动作用,即低层应该只管好自己的工作(具体实现),而高层自有它自己的工作(这就是管理低层的逻辑们),在不需要到某个低层的时候,高层并不会调用到这个具体低层,低层永远不需要向高层作出表示,,说它需要被调用,(即在所有的处于使用者与现有代码的中间的,用于隔离和解偶二者的,那些中间逻辑中,低层逻辑永远不要涉入高层的实现,而只要高层通过某个逻辑去涉入低层的实现,也即低层应不要调用高层,只有高层才会去调用低层,这才是合理的,我们应尽量避免向上调用和相互调用)。
由以上描述,依赖倒置原则明确了高低模块(细节)与抽象的依赖关系,好莱坞原则强调高层对低层的主动作用,两者在描述抽象与具体实现的依赖关系时候是完全一致的,所以有时候依赖倒置原则又被称为好莱坞原则。
2. 请描述一个你熟悉的框架,是如何实现依赖倒置原则的。
在spring的beanFactory加载过程中,AbstractBeanDefinitionReader类中有一个loadBeanDefinitions(Resource) 方法,这个方法将开始加载、解析 Bean 的定义,也就是把用户定义的数据结构转化为 Ioc 容器中的特定数据结构。具体代码如下:
从代码中中可以看到,AbstractBeanDefinitionReader类中是loadBeanDefinitions(Resource... resources)方法,但是这个方法是一个接口方法,具体实现在XmlBeanDefinitionReader中。在读取器中,需要得到代表XML文件的Resource,因为这个Resource对象封装了XML文件的I/O操作,所以读取器可以在打卡I/O流后得到XML的文件对象。有了这个对象后,就可以按照Spring的Bean定义规则来对这个文档树进行解析了,这个解析交给BeanDefinitionParserDelegate来完成。具体的时序图如下:
AbstractBeanDefinitionReader类的继承关系图:
Resource类结构关系图:
从上面的时序图和继承关系图中可以看到,在整个 Bean加载、解析过程中,无论涉及到相关对象和实体都进行了抽象,通过抽象完成了实现了整个Bean加载和解析的业务流程,整个业务逻辑只依赖抽象,并不是具体的实现。同时,在具体的实现过程中(如资源的解析的具体实现)只依赖于相应的抽象(Resource)。而这正好完美体现了依赖倒置原则的设计思想。
3. 请用接口隔离原则优化 Cache 类的设计,画出优化后的类图。
3.1 接口隔离原则
接口隔离原则的英文翻译是“ Interface Segregation Principle”,缩写为 ISP。Robert Martin 在 SOLID 原则中是这样定义它的:“Clients should not be forced to depend upon interfaces that they do not use。”直译成中文的话就是:客户端不应该被强迫依赖它不需要的接口。其中的“客户端”,可以理解为接口的调用者或者使用者。
3.2 分析提示
cache 实现类中有四个方法,其中 put get delete 方法是需要暴露给应用程序的,rebuild 方法是需要暴露给系统进行远程调用的。如果将 rebuild 暴露给应用程序,应用程序可能会错误调用 rebuild 方法,导致 cache 服务失效。按照接口隔离原则:不应该强迫客户程序依赖它们不需要的方法。也就是说,应该使 cache 类实现两个接口,一个接口包含 get put delete 暴露给应用程序,一个接口包含 rebuild 暴露给系统远程调用。从而实现接口隔离,使应用程序看不到 rebuild 方法。
3.2 设计类图(多重继承)
评论