软件设计原则之ISP接口隔离原则
(ISP) 接口隔离原则 Interface Segregation Principle
核心原则
不应该强迫客户程序依赖它们不用的方法。
场景描述
在大家的认知中,大多数鸟类都有翅膀并可以飞行。但是在奇妙的大自然中总有一些特例,如鸵鸟虽然有翅膀,但是不会飞行。
如果我们设计一个鸟的基类,并含有飞行相关方法,则这类方法将不适用于鸵鸟。
因此一些设计者会喜欢在这类方法中抛出异常或者使用断言的方式来进行处理。
#include <cassert> #include <iostream> class Bird { public: virtual void sleep() = 0; virtual void fly() = 0; }; // 鸽子 class Pigeon : public Bird { public: void sleep() override { std::cout << "The pigeon is sleeping" << '\n'; } void fly() override { std::cout << "The pigeon is flying" << '\n'; } }; // 鸵鸟 class Ostrich : public Bird { public: void sleep() override { std::cout << "The ostrich is sleeping" << '\n'; } void fly() override { std::cout << "The ostrich can not fly" << '\n'; assert(false); } }; int main() { Ostrich bird; bird.sleep(); // 鸵鸟不会飞,不合理 bird.fly(); }问题暴露
显然,既然方法是存在的,那难免会有不熟悉的开发者去调用它。并且在一些多态接口中,接口内部不知道外部传入的对象是什么,极有可能会去调用这些不合理的函数。
因此我们需要解耦,将各类方法的力度更加细化,不同的对象只去实现它应该并且能够实现的接口。
#include <cassert> #include <iostream> class CanSleep { public: virtual void sleep() = 0; }; class CanFly { public: virtual void fly() = 0; }; // 鸽子 class Pigeon : public CanSleep, public CanFly { public: void sleep() override { std::cout << "The pigeon is sleeping" << '\n'; } void fly() override { std::cout << "The pigeon is flying" << '\n'; } }; // 鸵鸟 class Ostrich : public CanSleep { public: void sleep() override { std::cout << "The ostrich is sleeping" << '\n'; } }; int main() { Ostrich bird; // 只使用,该对象可以使用的方法 bird.sleep(); }