敏捷软件开发–isp接口隔离原则

顾强 顾强     2022-08-04     599

关键词:

  如果类的接口不是内聚的,就表示该类具有“胖”接口。换句话说,类的“胖”接口可以分解成多组方法。每一组方法服务于一组不同的客户程序。

  ISP承认有一些对象确实需要有非内聚的接口,但是ISP建议客户程序不应该看到它们作为单一的类存在。相反,客户程序看到的应该是多个具有内聚接口的抽象基类。

接口污染

  考虑一个安全系统。在这个系统中,有一些Door对象,可以被加锁和解锁,并且Door对象知道自己是开着还是关着。这个Door编码成一个接口,这样客户程序就可以使用那些符合Door接口的对象,而不需要依赖于Door的特定实现。

public interface Door
{
    void Lock();
    void Unlock();
    bool IsDoorOpen();
}

  现在,考虑一个这样的实现,TimedDoor,如果门开着的时间过长,它就会发出警报声。为了实现这一点,TimedDoor对象需要和另外一个名为Timer的对象交互。

public class Timer
{
    public void Register(int timeout,TimerClient client)
    {}
}

public interface TimerClient
{
    void TimeOut();
}

  如果一个对象希望得到超时通知,它可以调用Timer的Register函数。该函数有两个参数,一个是超时时间,另一个是指向TimerClient对象的引用,其TimeOut函数会在超市到达时被调用。

  如何把TimerClient类和TimedDoor类联系起来,才能在超时时通知TimedDoor中相应的处理代码呢?

  常见的解决方案是,其中Door继承了TimerClient,因此TimedDoor也就继承了TimeClient。这就保证了TimerClient可以把自己注册到Timer中,并且可以接收TimeOut消息。

  这种做法的问题是,现在Door依赖于TimerClient了。可是并不是所有种类的Door都需要定时功能。事实上,最初的Door抽象类和定时功能没有任何关系。如果创建了无需定时功能的Door的派生类,那么在这些派生类中就必须要提供TimeOut方法的退化实现,这就可能违反ISP。此外,使用这些派生类的应用程序及时不使用TimerClient类的定义,也必须要引入它。这样就具有了不必要的复杂性以及不必要的重复性的臭味。

分离客户就是分离接口

  Door接口和TimerClient接口是被完全不同的客户程序使用的。Timer使用TimerClient,而操作门的类使用Door。既然客户程序是分离的,所以接口也应该保持分离。

  不应该强迫客户程序依赖并未使用的方法。

  如果强迫客户程序依赖于那些它们不使用的方法,那么这些客户程序就面临着由于这些未使用的方法的改变所带来的变更。这无意中导致了所有客户程序之间的耦合。换种说法,如果一个客户程序依赖于一个含有它不使用的方法的类,但是其他客户程序却确实要使用该方法,那么当其他客户要求这个类改变时,就会影响到这个客户程序。我们希望尽可能地避免这种耦合,因此我们希望分离接口。

类接口和对象接口

  再次考虑一下TimedDoor。它具有两个独立的接口,被两个独立的客户-Timer以及Door的使用者-使用。因此实现这两个接口需要操作同样的数据,所以这两个接口必须在同一个对象中实现。那么怎样才能遵循ISP呢?怎样才能分离必须在一起实现的接口呢?

  那就是一个对象的客户不必通过该对象的接口去访问它,也可以通过委托或者通过该对象的基类去访问它。

通过委托(适配器)分离接口

  一个解决方案是创建一个派生自TimerClient的对象,并把对该对象的请求传递给TimedDoor。

  当TimedDoor想要向Timer对象注册一个超时请求时,它就创建一个DoorTimerAdapter并且把它注册给Timer。当Timer对象发送TimeOut消息给DoorTimerAdapter时,DoorTimerAdapter把这个消息传递给TimedDoor。

  这个解决方案遵循了ISP原则,并且避免了Door的客户程序和Timer之间的耦合。即使对Timer进行了改变,也不会影响到任何Door的使用者。此外TimedDoor不必具有和TimerClient一样的接口。DoorTimerAdapter将TimerClient接口转换为TimedDoor接口。因此,这是一个通用的解决方案。

  不过,这个解决方案还是有些不太优雅。每次想去注册一个超时请求时,都要去创建一个新的对象。同时,类型转换会倒置一些很小但仍然存在的运行时间和内存的开销。

使用多重继承分离接口

   在这个模型中,TimedDoor同时继承了Door和TimerClient。尽管这两个基类的客户程序都可以使用TimedDoor,但是实际上却都不再依赖于TimedDoor。这样,它们就通过分离的接口使用同一对象。

  通常都会优先使用这个解决方案。

结论

  胖类会导致它们的客户程序之间产生不正常的并且有害的耦合关系。当一个客户程序要求该胖类进行一个改动时,会影响到所有其他的客户程序。因此,客户程序应该仅仅依赖于它们实际调用的方法。通过把胖类的接口分解为多个特定于客户程序的接口,可以实现这个目标。每个特定于客户程序的接口仅仅声明它的特定客户或者客户组调用的那些函数。接着,该胖类就可以继承所有特定于客户程序的接口,并实现它们。这就解除了客户程序和它们没有调用的方法间的依赖关系,并使客户程序之间互不依赖。

 

 

摘录自:[美]RobertC.Martin、MicahMartin著,邓辉、孙鸣译 敏捷软件开发原则、模式与实践(C#版修订版) [M]、人民邮电出版社,2013、115-121、

设计模式-六大设计原则之isp(接口隔离原则)(代码片段)

文章目录概述CaseBadImplBetterImpl概述接口隔离原则(InterfaceSegregationPrinciple,ISP),要求尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含相关的方法。接口隔离是为了高内聚、低耦合。在实际的开发... 查看详情

设计原则-isp接口隔离原则

1.定义客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上。2.分析接口隔离原则是对接口的使用进行约束规范的一个原则,它告诉我们要想把接口用好,关键在于隔离。接口隔离原则告诉我们,不要把... 查看详情

接口隔离原则(interfacesegregationprinciple,isp)(代码片段)

接口隔离原则:1.使用多个专门的接口比使用单一的总接口要好。2.一个类对另外一个类的依赖性应当是建立在最小的接口上的。3.一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成... 查看详情

接口隔离原则|solidasarock

文章目录意图动机:违反接口隔离原则解决方案:C++中接口隔离原则的例子接口隔离原则的优点1、编译更快2、可复用性3、可维护性在C++中用好ISP的标准费几句话本文是关于SOLIDasRock设计原则系列的五部分中的第四部分。SOLID设... 查看详情

设计模式-六大设计原则之isp(接口隔离原则)(代码片段)

文章目录概述CaseBadImplBetterImpl概述接口隔离原则(InterfaceSegregationPrinciple,ISP),要求尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含相关的方法。接口隔离是为了高内聚、低耦合。在实际的开发... 查看详情

面向对象设计原则七:接口隔离原则

接口隔离原则(ISP)  定义:使用多个专门的接口比使用单一的总接口要好。即不要把鸡蛋都放到一个篮子里。  好处:比较灵活、方便,不想实现的或不用实现的可以不实现。解释说明:  大部分人都喜欢用一个接口把... 查看详情

oop面向对象编程设计原则-接口隔离原则

接口隔离原则(英语:interface-segregationprinciples,缩写:ISP)指明客户(client)不应被迫使用对其而言无用的方法或功能。接口隔离原则(ISP)拆分非常庞大臃肿的接口成为更小的和更具体的接... 查看详情

设计模式:面向对象的设计原则下(isp、dip、kiss、dry、lod)

参考技术A作者:oec2003公众号:不止dotNET本文继续来介绍接口隔离原则(ISP)和依赖倒置原则(DIP),这两个原则都和接口和继承有关。文章最后会简单介绍几个除了SOLID原则之外的原则。提起接口,开发人员的第一反应可能是... 查看详情

面向对象设计原则之接口隔离原则

   接口隔离原则定义如下:接口隔离原则(Interface SegregationPrinciple,ISP):使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。      根据接口隔离原则,当一个接口太... 查看详情

软件工程设计原则

...一职责原则SRP类的职责单一依赖倒转原则DIP针对抽象(或接口)编程,而不针对具体编程接口隔离原则ISP使用多个专门接口要优于使用单一的接口组合聚合原则CRP优先使用组合或聚合关系,不要过于使用继承关系迪米特原则LoD一... 查看详情

c#实例解释面向对象编程中的接口隔离原则(代码片段)

...ff1a;里氏替换原则(Liskovsubstitutionprinciple)I:接口隔离原则(Interfacesegregationprinciple)D:依赖反转原则(Dependencyinversionprinciple)本文我们来介绍接口隔离原则。接口隔离原则接口隔离原则(Inter... 查看详情

软件设计原则

...----修改封闭。3、DIP:依赖倒置原则,一个类尽量依赖于接口等高端类(父类),尽量避免依赖于子类。4、SRP:单一职责原则,类功能越少越好。二、松耦合1、LOD:迪米特法则,即朋友最少原则,为了减少类之间的关系相互影... 查看详情

设计模式软件设计七大原则(接口隔离原则|代码示例)(代码片段)

文章目录一、接口隔离原则简介二、接口隔离原则代码示例(反面示例)1、接口定义(接口臃肿)2、实现类13、实现类2三、接口隔离原则代码示例(推荐用法)1、接口12、接口23、接口34、接口45、实现类一、接口隔离原则简介接口隔离... 查看详情

搞定设计模式之接口隔离原则一篇文章就够了!!!(代码片段)

...不使用的方法一个类对另一个类的依赖应该建立在最小的接口上接口隔离原则(InterfaceSegregationPrinciple,ISP)要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法。... 查看详情

面象对象设计6大原则之四:接口隔离原则

接口隔离原则(ISP),TheInterfaceSegregationPrinciple 定义客户端不需要强迫依赖那些它们不需要的接口。类与接口的依赖应该建议在最小的接口上,也就是说接口应该最小化,不能建立在一个庞大的接口之上,接口合理地按功能... 查看详情

面向对象设计原则接口分离原则(interfacesegregationprinciple)

接口隔离原则 使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。 从接口隔离原则的定义可以看出,他似乎跟SRP有许多相似之处。是的其实ISP和SRP都是强调职责的单一性,接口隔离... 查看详情

软件架构设计原则-接口隔离原则(代码片段)

前言接口隔离原则是指用多个专门的接口,而不适用单一的总接口,接下来,我们一个实际的案例来解释案例首先我们定义一个动物类IAnimal接口,接口有eat、fly、swim三种活动publicinterfaceIAnimalvoideat();voidfly();voidswim... 查看详情

java设计模式5,接口隔离原则(代码片段)

目录一、接口隔离原则二、模拟场景三、违背原则方案1、程序员的职责接口2、项目经理3、开发人员4、测试人员四、接口隔离原则概述代码1、设计接口2、开发接口3、测试接口4、运维接口5、项目经理6、开发人员7、测试人员一... 查看详情