设计模式七大原则---接口隔离原则

一、概念

接口隔离原则(Interface Segregation Principle,ISP):
使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

根据接口隔离原则,当一个接口太大时,我们需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。这里的“接口”往往有两种不同的含义:一种是指一个类型所具有的方法特征的集合,仅仅是一种逻辑上的抽象;另外一种是指某种语言具体的“接口”定义,有严格的定义和结构,比如Java语言中的interface。对于这两种不同的含义,ISP的表达方式以及含义都有所不同:

(1)
当把“接口”理解成一个类型所提供的所有方法特征的集合的时候,这就是一种逻辑上的概念,接口的划分将直接带来类型的划分。可以把接口理解成角色,一个接口只能代表一个角色,每个角色都有它特定的一个接口,此时,这个原则可以叫做“角色隔离原则”。

(2)
如果把“接口”理解成狭义的特定语言的接口,那么ISP表达的意思是指接口仅仅提供客户端需要的行为,客户端不需要的行为则隐藏起来,应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口。在面向对象编程语言中,实现一个接口就需要实现该接口中定义的所有方法,因此大的总接口使用起来不一定很方便,为了使接口的职责单一,需要将大接口中的方法根据其职责不同分别放在不同的小接口中,以确保每个接口使用起来都较为方便,并都承担某一单一角色。接口应该尽量细化,同时接口中的方法应该尽量少,每个接口中只包含一个客户端(如子模块或业务逻辑类)所需的方法即可,这种机制也称为“定制服务”,即为不同的客户端提供宽窄不同的接口

二、示例

在这里插入图片描述
在实际使用过程中发现该接口很不灵活,例如如果一个具体的数据显示类无须进行数据转换(源文件本身就是XML格式),但由于实现了该接口,将不得不实现其中声明的transformToXML()方法(至少需要提供一个空实现);如果需要创建和显示图表,除了需实现与图表相关的方法外,还需要实现创建和显示文字报表的方法,否则程序编译时将报错。

  现使用接口隔离原则对其进行重构。

在图1中,由于在接口CustomerDataDisplay中定义了太多方法,即该接口承担了太多职责,一方面导致该接口的实现类很庞大,在不同的实现类中都不得不实现接口中定义的所有方法,灵活性较差,如果出现大量的空方法,将导致系统中产生大量的无用代码,影响代码质量;另一方面由于客户端针对大接口编程,将在一定程序上破坏程序的封装性,客户端看到了不应该看到的方法,没有为客户端定制接口。因此需要将该接口按照接口隔离原则和单一职责原则进行重构,将其中的一些方法封装在不同的小接口中,确保每一个接口使用起来都较为方便,并都承担某一单一角色,每个接口中只包含一个客户端(如模块或类)所需的方法即可。

  通过使用接口隔离原则,本实例重构后的结构如图2所示:

在这里插入图片描述

三、代码

臃肿(多余方法)接口设计,称之为胖接口,一点接口方法变动,会影响所有实现该接口的客户端类程序,比如当在行为类中增加新的动作接口时,如“爬行”,需要在所有派生动物类中重写爬行方法,耦合度过高。

违背”客户端类不应依赖不需要的接口”原则

#include <iostream>

class IFlyBehavior {
public:
    virtual void fly() = 0;
};
class ISwimBehavior {
public:
    virtual void swim() = 0;
};

class Fish : public ISwimBehavior {
    virtual void swim() {
        std::cout <<"我是鱼游泳真快乐!"<<std::endl;
    }
};

class Bird : public IFlyBehavior {
    virtual void fly()  {
        std::cout <<"我是鸟儿飞行真快乐!"<<std::endl;
    }
};

class Yazi : public IFlyBehavior, public ISwimBehavior{
    virtual void fly()  {
        std::cout <<"我是鸭子飞行真快乐!"<<std::endl;
    }
    virtual void swim()  {
        std::cout <<"我是鸭子游泳真快乐!"<<std::endl;
    }
};

class Zoo {
public:
    void showSwim(ISwimBehavior* behavior) {
        behavior->swim();
    }
    void showFly(IFlyBehavior* behavior) {
        behavior->fly();
    }
};

int main() {
    Zoo z;
    Fish* fish = new Fish();
    Bird* bird = new Bird();

    Yazi* yazi = new Yazi();

    z.showSwim(fish);
    z.showFly(bird);

    z.showSwim(yazi);
    z.showFly(yazi);

    return 1;
}

增加动物行为类的方法时,不影响现有鸟类、鱼类功能(不需要做任何变更)

增加动物类别时,比如鸭子类,只需要按照需要多重继承需要的接口即可,比如飞行行为类、游泳行为类。

————————————————
版权声明:本文为CSDN博主「龙俊杰的读书笔记」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011852872/article/details/126048630
————————————————
版权声明:本文为CSDN博主「LoveLion」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lovelion/article/details/7562842

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值