设计模式六大原则之--接口隔离原则(ISP)
来源:互联网 发布:java的数组怎么定义 编辑:程序博客网 时间:2024/05/29 04:53
1.接口隔离原则:(Interface Segregation Principle, ISP)
定义:Clients should not be forced to depend upon interfaces that they don't use.(客户端不应该依赖它不需要的接口)。或
The dependcy of one class to another one should depend on the smallest possible interface.(类间的依赖关系应该建立在最小的接口上)。或
使用多个专门的接口比使用单一的总接口要好。
2.理解:
接口隔离原则的含义是:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。 在程序设计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。接口是设计时对外部设定的“契约”,通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
单一职责与接口隔离的区别:
- 单一职责原则注重的是职责;而接口隔离原则注重对接口依赖的隔离。
- 单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节; 而接口隔离原则主要约束接口,主要针对抽象,针对程序整体框架的构建。
- 原则意义上的好处:接口如果能够保持粒度够小,就能保证它足够稳定,正如单一职责原则所飘洋过海榜的那样。(举例:多个专门的接口就好比采用活字制版,可以随时拼版拆版,既利于修改,又利于文字的重用。而单一的总接口就是雕版的印刷,一旦发现错别字,既难改,又需要整块重新雕刻。)
- 使用多个专门的接口还能够体现对象的层次,因为我们可以通过接口的继承,实现对总接口的定义。(例如,.NET框架中IList接口的定义。)
- public interface IEnumerable
- {
- IEnumerator GetEnumerator();
- }
- public interface ICollection : IEnumerable
- {
- void CopyTo(Array array, int index);
- // 其余成员略
- }
- public interface IList : ICollection, IEnumerable
- {
- int Add(object value);
- void Clear();
- bool Contains(object value);
- int IndexOf(object value);
- void Insert(int index, object value);
- void Remove(object value);
- void RemoveAt(int index);
- // 其余成员略
- }
如果不采用这样的接口继承方式,而是定义一个总的接口包含上述成员,就无法实现IEnumerable接口、ICollection接口与IList接口成员之间的隔离。假如这个总接口名为IGeneralList,它抹平了IEnumerable接口、ICollection接口与IList接口之间的差别,包含了它们的所有方法。现在,如果我们需要定义一个Hashtable类。根据数据结构的特性,它将无法实现IGeneralList接口。因为Hashtable包含的Add()方法,需要提供键与值,而之前针对ArrayList的Add()方法,则只需要值即可。这意味着两者的接口存在差异。我们需要专门为Hashtable定义一个接口,例如IDictionary,但它却与IGeneralList接口不存在任何关系。正是因为一个总接口的引入,使得我们在可枚举与集合层面上丢失了共同的抽象意义。虽然Hashtable与ArrayList都是可枚举的,也都具备集合特征,它们却不可互换。
如果遵循接口隔离原则,将各自的集合操作功能分解为不同的接口,那么站在ICollection以及IEnumerable的抽象层面上,可以认为ArrayList和Hashtable是相同的对象。在这一抽象层面上,二者是可替换的,如图2-9所示。这样的设计保证了一定程度的重用性与可扩展性。从某种程度来讲,接口隔离原则可以看做是接口层的单一职责原则。
倘若一个类实现了所有的专门接口,从实现上看,它与实现一个总接口的方式并无区别;但站在调用者的角度,不同的接口代表了不同的关注点、不同的职责,甚至是不同的角色。因此,面对需求不同的调用者,这样的类就可以提供一个对应的细粒度接口去匹配。此外,一个庞大的接口不利于我们对其进行测试,因为在为该接口实现Mock或Fake对象 时,需要实现太多的方法。
概括地讲,面向对象设计原则仍然是面向对象思想的体现。例如,单一职责原则与接口隔离原则体现了封装的思想,开放封闭原则体现了对象的封装与多态,而Liskov替换原则是对对象继承的规范,至于依赖倒置原则,则是多态与抽象思想的体现。在充分理解面向对象思想的基础上,掌握基本的设计原则,并能够在项目设计中灵活运用这些原则,就能够改善我们的设计,尤其能够保证可重用性、可维护性与可扩展性等系统的质量属性。这些核心要素与设计原则,就是我们设计的对象法则,它们是理解和掌握设计模式的必备知识。
- 接口要尽量小(核心定义),但“小”也有限,首先不能违反单一职责原则(接口定义出来是让类来实现的嘛,倘若如此,实现类怎么来SRP?)(去看SRP的7.2节);
- 接口要高内聚(高内聚:提高接口、类、模块的处理能力,减少对外的交互。例如,不讲任何条件、立刻完成任务的行为就是高内聚的表现),具体到接口隔离原则 ,就是要求在接口中尽量少公布public方法,接口是对外的承诺,承诺越少对系统的开发越有利,变更的风险也就越少,同时也有利于降低成本;
- 定制服务,一个系统或系统内的模块之间必然会有耦合,有耦合就要有相互访问的接口,在设计时,就需要为各个访问者定制服务(定制服务就是单独为一个个体提供优良的服务:只提供访问者需要的方法),本质也是ISP,按需拆分接口;
- 接口设计是有限度的,但无固化标准。
- 一个接口只服务于一个子模块或业务逻辑;
- 通过业务逻辑压缩接口中的public方法,接口时常去回顾,尽量让接口达到“筋骨”,而不是“肥嘟嘟”的一大堆方法;
- 已经被 污染的接口,要尽量去修改,若变更的风险较大,则采用适配器模式进行转化处理;
- 了解环境,拒绝盲从。
- interface I {
- public void method1();
- public void method2();
- public void method3();
- public void method4();
- public void method5();
- }
- class A{
- public void depend1(I i){
- i.method1();
- }
- public void depend2(I i){
- i.method2();
- }
- public void depend3(I i){
- i.method3();
- }
- }
- class B implements I{
- public void method1() {
- System.out.println("类B实现接口I的方法1");
- }
- public void method2() {
- System.out.println("类B实现接口I的方法2");
- }
- public void method3() {
- System.out.println("类B实现接口I的方法3");
- }
- //对于类A来说,method4和method5不是必须的,但是由于接口A中有这两个方法,
- //所以在实现过程中即使这两个方法的方法体为空,也要将这两个没有作用的方法进行实现。
- public void method4() {}
- public void method5() {}
- }
- class C{
- public void depend1(I i){
- i.method1();
- }
- public void depend2(I i){
- i.method4();
- }
- public void depend3(I i){
- i.method5();
- }
- }
- class D implements I{
- public void method1() {
- System.out.println("类D实现接口I的方法1");
- }
- //对于类C来说,method4和method5不是必须的,但是由于接口A中有这两个方法,
- //所以在实现过程中即使这两个方法的方法体为空,也要将这两个没有作用的方法进行实现。
- public void method2() {}
- public void method3() {}
- public void method4() {
- System.out.println("类D实现接口I的方法4");
- }
- public void method5() {
- System.out.println("类D实现接口I的方法5");
- }
- }
- public class Client{
- public static void main(String[] args){
- A a = new A();
- a.depend1(new B());
- a.depend2(new B());
- a.depend3(new B());
- C c = new C();
- c.depend1(new D());
- c.depend2(new D());
- c.depend3(new D());
- }
- }
- interface I1 {
- public void method1();
- }
- interface I2 {
- public void method2();
- public void method3();
- }
- interface I3 {
- public void method4();
- public void method5();
- }
- class A{
- public void depend1(I1 i){
- i.method1();
- }
- public void depend2(I2 i){
- i.method2();
- }
- public void depend3(I2 i){
- i.method3();
- }
- }
- class B implements I1, I2{
- public void method1() {
- System.out.println("类B实现接口I1中的方法1");
- }
- public void method2() {
- System.out.println("类B实现接口I2中的方法2");
- }
- public void method3() {
- System.out.println("类B实现接口I2中的方法3");
- }
- }
- class C{
- public void depend1(I1 i){
- i.method1();
- }
- public void depend2(I3 i){
- i.method4();
- }
- public void depend3(I3 i){
- i.method5();
- }
- }
- class D implements I1, I3{
- public void method1() {
- System.out.println("类D实现接口I1中的方法1");
- }
- public void method4() {
- System.out.println("类D实现接口I3中的方法4");
- }
- public void method5() {
- System.out.println("类D实现接口I3中的方法5");
- }
- }
- 设计模式六大原则之--接口隔离原则(ISP)
- 设计模式六大原则之--接口隔离原则(ISP)
- 设计模式之六大原则——接口隔离原则(ISP)
- 设计模式之六大原则——接口隔离原则(ISP)
- 设计模式之六大原则——接口隔离原则(ISP)
- 设计模式之六大原则——接口隔离原则(ISP)
- IOS设计模式的六大设计原则之接口隔离原则(ISP,Interface Segregation Principle)
- 六大原则之“接口隔离原则(ISP)“笔记
- 设计模式六大原则(4):接口隔离原则ISP(Interface Segregation Principle)
- 设计模式六大原则(一)-- 接口隔离原则(ISP)
- 设计模式六大原则例子(一)-- 接口隔离原则(ISP)例子
- 设计模式六大原则——接口隔离原则(ISP,Interface Segregation Principle)
- 设计模式无限重读之接口隔离原则(ISP)
- 设计模式原则—接口隔离原则(ISP)
- 设计原则之接口隔离原则(ISP)
- 设计模式六大原则:接口隔离原则
- 设计模式六大原则:接口隔离原则
- 设计模式六大原则----------接口隔离原则
- c++ list, vector, map, set 区别与用法比较
- 移动端问题汇总
- Python中expected an indented block
- sqlite数据库中的sql语句
- StringBuilder类中常用的重要方法
- 设计模式六大原则之--接口隔离原则(ISP)
- 计算一个坐标点是否在一个矩形或者多边形内
- fir.im Weekly - iOS / Android 动态化更新方案盘点
- 《从零开始学Swift》学习笔记(Day 59)——代码排版
- Java获取系统属性及环境变量
- 软件开发生命周期
- C++关于运算符的优先级
- python库函数安装方法
- 【Unity资源】(模型/道具)