设计模式-02 设计模式-接口隔离原则案例分析

1.定义

接口隔离原则(Interface Segregation Principle,简称 ISP)是设计模式中的一个原则,它规定客户端不应该依赖它不使用的方法。

换句话说,接口应该被细分为更小的、更具体的接口,以便客户端只依赖于它们需要的方法。

bash 复制代码
										(客户端)
                                           |
                                           V
                   (公共行为)            (特定行为)         (特定行为)
                    +------------+         +-------------+        +-------------+
                    |  I公共接口  |         | I特定接口1 |        | I特定接口2 |
                    +------------+         +-------------+        +-------------+
                              |               |              |
                              V               V              V
                           +-------+     +---------+     +---------+
                           | 客户端1 |     | 客户端2 |     | 客户端3 |
                           +-------+     +---------+     +---------+
2.内涵

接口应该被细分的足够少,接口与接口直接不应该有依赖,ISP 的目的是提高代码的灵活性、可维护性和可测试性。总结起来,ISP原则的好处和缺点如下。

ISP 的好处

  • 提高代码的灵活性
  • 提高代码的可维护性
  • 提高代码的可测试性
  • 减少耦合
  • 提高代码的可重用性

ISP 的缺点

  • 可能导致更多的接口
  • 可能增加代码的复杂性
3.案例对比

例如,以机器类的定义为例,假如一个机器可以打印机,复印机,发传真机,如果不加以深入思考,我们可能如下第一种方式定义。

bad 设计

cpp 复制代码
//
// Created by Administrator on 2024/5/1.
//
#include <iostream>
using namespace std;
struct Document;
struct IMachine{
    virtual void print(Document& doc) = 0;
    virtual void scan(Document& doc) = 0;
    virtual void fax(Document& doc) = 0;

};
// 接口分离原则

// 发现 MFP  只需要 print 功能即可
// 其他接口到底怎么处理比较好?
struct MFP:IMachine{
    void print(Document &doc) override {
        // ok
    }

    void scan(Document &doc) override {

    }

    void fax(Document &doc) override {

    }
};

// 发现scanner 只需要 scan 功能
// 其他接口到底怎么处理比较好?
struct Scanner:IMachine{
    void print(Document &doc) override {
        // do what?
    }

    void scan(Document &doc) override {
        // ok
    }

    void fax(Document &doc) override {
        // do what?
    }
};

如果后面的传真机怎么定义?,除了fax 函数外,其他函数的功能并不是fax 需要的。

好的设计

cpp 复制代码
#include <iostream>
using namespace std;
struct Document;


// 接口分离
struct IPrinter{
    virtual void print(Document& doc) =0 ;
};

struct IScanner {
    virtual void scan(Document& doc)=0 ;
};

struct IFax{
    virtual void fax(Document& doc)=0 ;
};

struct IMachine:IPrinter,IScanner {

};

struct Machine:IMachine{
    IPrinter& printer;
    IScanner& scanner;
    Machine(IPrinter &printer, IScanner &scanner):printer(printer),scanner(scanner){

    }

    void print(Document &doc) override {
        printer.print(doc);
    }

    void scan(Document &doc) override {
        scanner.scan(doc);
    }
};

这种设计,我们可以任意进行组合,组合出不同特性的子类,自由度更高。

4.注意事项

在实际开发中应用接口隔离原则(ISP)时,需要注意以下几点:

  • 识别公共行为。第一步是识别客户端共享的公共行为。这些行为可以被抽象到一个公共接口中。
  • 细化接口。对于任何不属于公共行为的方法,都应该将其细化到一个单独的接口中。
  • 考虑可扩展性。在设计接口时,考虑未来的可扩展性。避免将不相关的功能包含在同一个接口中。
  • 使用依赖注入。依赖注入是一种技术,它允许客户端只依赖于它们需要的接口。这有助于实现松耦合和可测试性。
  • 避免使用继承。继承是一种实现代码重用的强大机制,但它也可能导致违反 ISP。如果可能的话,优先使用组合而不是继承。
5.最佳实践

注意的具体示例:

  • 避免创建上帝接口。上帝接口是一个包含大量方法的大型接口。客户端通常只使用其中一小部分方法,但仍然必须实现所有方法。这违反了 ISP,并可能导致不必要的代码和维护开销。
  • 避免使用可选方法。可选方法允许客户端选择性地实现接口中的某些方法。这可能导致代码混乱和不可预测的行为。如果可能的话,避免使用可选方法,而是创建单独的接口来表示可选的行为。
  • 考虑未来需求。在设计接口时,考虑未来的需求。避免将不相关的功能包含在同一个接口中,因为这可能会限制接口的未来可扩展性。
6.总结

应用 ISP 时,权衡其优点和缺点非常重要。ISP 可以提高代码的灵活性、可维护性和可测试性,但它也可能导致更多的接口和增加代码的复杂性。

总体而言,ISP 是一个有用的设计原则,它可以帮助提高代码的质量。通过遵循上述准则,开发人员可以有效地应用 ISP,从而获得其好处,同时避免其潜在的缺点。

相关推荐
蜡笔小新..1 天前
【设计模式】软件设计原则——开闭原则&里氏替换&单一职责
java·设计模式·开闭原则·单一职责原则
性感博主在线瞎搞1 天前
【面向对象】设计模式概念和分类
设计模式·面向对象·中级软件设计师·设计方法
lucifer3111 天前
JavaScript 中的组合模式(十)
javascript·设计模式
lucifer3111 天前
JavaScript 中的装饰器模式(十一)
javascript·设计模式
蜡笔小新..1 天前
【设计模式】软件设计原则——依赖倒置&合成复用
设计模式·依赖倒置原则·合成复用原则
刷帅耍帅1 天前
设计模式-代理模式
设计模式·代理模式
神的孩子都在歌唱1 天前
行为设计模式 -观察者模式- JAVA
java·观察者模式·设计模式
刷帅耍帅2 天前
设计模式-解释器模式
设计模式·解释器模式
刷帅耍帅2 天前
设计模式-备忘录模式
设计模式·备忘录模式