组建构建过程中某些接口之间直接的依赖往往会带来许多问题。甚至根本无法实现。采用添加一层间接稳定的接口的方式来隔离。本来互相紧密关联的接口是一种常见的解决方式。
接口隔离原则(Interface Segregation Principle, ISP)是面向对象设计中的一个重要原则。它强调不应强迫客户端依赖于他们不需要的方法,而应将接口拆分成更小和更具体的接口,使得客户端只需知道它们需要的方法。
在实际的软件设计中,有几个设计模式能够帮助实现接口隔离原则:
动机: 将一个接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
实现:
代码示例:
class ITarget { public: virtual void request() = 0; }; class Adaptee { public: void specificRequest() { std::cout << "Adaptee specific request." << std::endl; } }; class Adapter : public ITarget { private: Adaptee* adaptee; public: Adapter(Adaptee* adaptee) : adaptee(adaptee) {} void request() override { adaptee->specificRequest(); } };
动机: 动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更为灵活。
实现:
代码示例:
class Component { public: virtual void operation() = 0; }; class ConcreteComponent : public Component { public: void operation() override { std::cout << "ConcreteComponent operation." << std::endl; } }; class Decorator : public Component { protected: Component* component; public: Decorator(Component* component) : component(component) {} void operation() override { component->operation(); } }; class ConcreteDecorator : public Decorator { public: ConcreteDecorator(Component* component) : Decorator(component) {} void operation() override { Decorator::operation(); std::cout << "ConcreteDecorator additional operation." << std::endl; } };
动机: 将抽象部分与它的实现部分分离,使它们都可以独立地变化。
实现:
代码示例:
class Implementor { public: virtual void operationImpl() = 0; }; class ConcreteImplementorA : public Implementor { public: void operationImpl() override { std::cout << "ConcreteImplementorA operation." << std::endl; } }; class Abstraction { protected: Implementor* implementor; public: Abstraction(Implementor* implementor) : implementor(implementor) {} virtual void operation() { implementor->operationImpl(); } }; class RefinedAbstraction : public Abstraction { public: RefinedAbstraction(Implementor* implementor) : Abstraction(implementor) {} void operation() override { implementor->operationImpl(); } };
动机: 为其他对象提供一种代理以控制对这个对象的访问。
实现:
代码示例:
class Subject { public: virtual void request() = 0; }; class RealSubject : public Subject { public: void request() override { std::cout << "RealSubject request." << std::endl; } }; class Proxy : public Subject { private: RealSubject* realSubject; public: Proxy(RealSubject* realSubject) : realSubject(realSubject) {} void request() override { if (realSubject == nullptr) { realSubject = new RealSubject(); } realSubject->request(); } };
动机: 定义一系列算法,并将它们封装起来,使它们可以相互替换,本模式使得算法可独立于使用它的客户而变化。
实现:
代码示例:
class Strategy { public: virtual void algorithm() = 0; }; class ConcreteStrategyA : public Strategy { public: void algorithm() override { std::cout << "ConcreteStrategyA algorithm." << std::endl; } }; class ConcreteStrategyB : public Strategy { public: void algorithm() override { std::cout << "ConcreteStrategyB algorithm." << std::endl; } }; class Context { private: Strategy* strategy; public: Context(Strategy* strategy) : strategy(strategy) {} void setStrategy(Strategy* strategy) { this->strategy = strategy; } void executeAlgorithm() { strategy->algorithm(); } };
接口隔离原则强调将大接口拆分成更小的、更加具体的接口,以便客户端只依赖于它们实际需要的接口。上述设计模式在一定程度上体现了这一原则,通过这些模式的合理运用,可以设计出更加灵活和可维护的系统。
这张图展示了系统设计中关于系统间耦合复杂度减少的一种对比方案。具体来说,图中分为A方案和B方案两种系统设计方案,通过这两种方案的对比,阐述了如何通过设计模式(特别是Facade模式)来降低系统间的耦合复杂度,从而提高系统的可维护性和可扩展性。
描述:
在A方案中,客户端类(client classes)与子系统类(subsystem classes)之间存在直接耦合。这意味着客户端类直接依赖于多个子系统类,这种直接依赖关系增加了系统的耦合度,使得系统变得复杂且难以维护。当子系统发生变化时,客户端类也需要进行相应的修改,这违反了开闭原则(软件实体应当对扩展开放,对修改关闭)。
问题:
直接耦合导致系统结构紧密,修改成本高,且不利于系统的扩展和维护。
描述:
优势:
为此系统中的一组接口提供了一个一致稳定的界面。门面模式是定义了一个高层接口,这个接口使得这一子系统更容易的使用和复用。
这张门面模式(Facade Pattern)结构示意图清晰地展示了该设计模式在软件架构中的应用。门面模式是一种结构型设计模式,它为子系统中的一组接口提供一个统一的接口,使得这一子系统更加容易使用。在这个示意图中,各个元素和它们之间的关系被巧妙地描绘出来,以便理解门面模式的工作原理。
结构(Structure):
Facade:
子系统类(subsystem classes):
整个示意图通过简洁的线条和清晰的标签,展示了门面模式在软件系统中的应用。客户端(尽管未在图中直接显示)通过门面与子系统交互,而不需要知道子系统内部的具体实现细节。这种设计使得系统更加模块化,易于管理和维护。同时,它也使得系统更加灵活,因为当子系统内部发生变化时,只要门面接口保持不变,客户端代码就无需修改。
综上所述,这张门面模式结构示意图通过直观的方式展示了该设计模式在软件架构中的关键作用,即提供一个简化的接口来封装子系统的复杂性。系统的复杂性。