设计模式-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,从而获得其好处,同时避免其潜在的缺点。

相关推荐
晨米酱18 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
数据智能老司机1 天前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机1 天前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——性能模式
python·设计模式·架构
使一颗心免于哀伤1 天前
《设计模式之禅》笔记摘录 - 21.状态模式
笔记·设计模式
数据智能老司机2 天前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
数据智能老司机2 天前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
烛阴2 天前
【TS 设计模式完全指南】懒加载、缓存与权限控制:代理模式在 TypeScript 中的三大妙用
javascript·设计模式·typescript
李广坤2 天前
工厂模式
设计模式