设计模式15-门面模式
"接口隔离"模式
组建构建过程中某些接口之间直接的依赖往往会带来许多问题。甚至根本无法实现。采用添加一层间接稳定的接口的方式来隔离。本来互相紧密关联的接口是一种常见的解决方式。
典型模式
接口隔离原则(Interface Segregation Principle, ISP)是面向对象设计中的一个重要原则。它强调不应强迫客户端依赖于他们不需要的方法,而应将接口拆分成更小和更具体的接口,使得客户端只需知道它们需要的方法。
在实际的软件设计中,有几个设计模式能够帮助实现接口隔离原则:
1. 适配器模式(Adapter Pattern)
动机: 将一个接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
实现:
- 类适配器模式:通过多重继承实现,适配器继承自适配者类和目标接口。
- 对象适配器模式:通过组合实现,适配器持有适配者对象的实例。
代码示例:
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(); } };
2. 装饰模式(Decorator Pattern)
动机: 动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更为灵活。
实现:
- 使用一个抽象接口和具体的装饰类,这些装饰类可以在运行时动态地添加行为到对象中。
代码示例:
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; } };
3. 桥接模式(Bridge Pattern)
动机: 将抽象部分与它的实现部分分离,使它们都可以独立地变化。
实现:
- 抽象类和实现类通过桥接模式分离开来,可以独立地对其进行扩展和变化。
代码示例:
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(); } };
4. 代理模式(Proxy Pattern)
动机: 为其他对象提供一种代理以控制对这个对象的访问。
实现:
- 使用代理类来控制对实际对象的访问,代理类实现了实际对象的接口。
代码示例:
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(); } };
5. 策略模式(Strategy Pattern)
动机: 定义一系列算法,并将它们封装起来,使它们可以相互替换,本模式使得算法可独立于使用它的客户而变化。
实现:
- 定义一个策略接口和具体的策略实现类,客户端通过组合的方式使用策略接口来实现不同的行为。
代码示例:
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方案
描述:
在A方案中,客户端类(client classes)与子系统类(subsystem classes)之间存在直接耦合。这意味着客户端类直接依赖于多个子系统类,这种直接依赖关系增加了系统的耦合度,使得系统变得复杂且难以维护。当子系统发生变化时,客户端类也需要进行相应的修改,这违反了开闭原则(软件实体应当对扩展开放,对修改关闭)。
问题:
直接耦合导致系统结构紧密,修改成本高,且不利于系统的扩展和维护。
B方案
描述:
- 为了解决A方案中的问题,B方案引入了Facade模式。Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。在B方案中,Facade作为客户端类和子系统类之间的中介,客户端类不再直接与子系统类交互,而是通过Facade来进行交互。这样,客户端类与子系统类之间的耦合度大大降低,客户端类只需与Facade交互即可,无需了解子系统类的内部细节。
优势:
- Facade模式降低了系统的耦合度,提高了系统的灵活性和可维护性。当子系统内部发生变化时,客户端类无需修改,只需调整Facade即可,从而降低了修改成本和风险。
定义
为此系统中的一组接口提供了一个一致稳定的界面。门面模式是定义了一个高层接口,这个接口使得这一子系统更容易的使用和复用。
结构
这张门面模式(Facade Pattern)结构示意图清晰地展示了该设计模式在软件架构中的应用。门面模式是一种结构型设计模式,它为子系统中的一组接口提供一个统一的接口,使得这一子系统更加容易使用。在这个示意图中,各个元素和它们之间的关系被巧妙地描绘出来,以便理解门面模式的工作原理。
主要元素解释
结构(Structure):
- 这个词在图中可能指代整个软件系统的结构,特别是与门面模式相关的那部分结构。它强调了系统内部的组织和关系,尤其是门面如何作为这些内部结构的对外接口。
Facade:
- 门面是此设计模式的核心。在图中,Facade被明确标出,作为子系统(subsystem classes)与客户端(未直接显示在图中)之间的中介。门面类为子系统提供了一个简化的接口,客户端通过这个接口与子系统交互,而无需直接与子系统中的多个类打交道。这样做的好处是降低了系统的耦合度,提高了系统的可维护性和可扩展性。
子系统类(subsystem classes):
- 这些是系统中实际执行功能的类。在图中,虽然文本“suhsysiem ciasses”似乎是“subsystem classes”的拼写错误,但我们可以推断出它指的是多个子系统类。这些类之间可能存在复杂的依赖和交互关系,但通过使用门面模式,这些复杂性被封装在子系统内部,对外部客户端透明。
示意图的整体解释
整个示意图通过简洁的线条和清晰的标签,展示了门面模式在软件系统中的应用。客户端(尽管未在图中直接显示)通过门面与子系统交互,而不需要知道子系统内部的具体实现细节。这种设计使得系统更加模块化,易于管理和维护。同时,它也使得系统更加灵活,因为当子系统内部发生变化时,只要门面接口保持不变,客户端代码就无需修改。
综上所述,这张门面模式结构示意图通过直观的方式展示了该设计模式在软件架构中的关键作用,即提供一个简化的接口来封装子系统的复杂性。系统的复杂性。
要点总结
- 从客户程序的角度来看,门面模式简化了一个组件系统的接口。组建内部与外部客户程序来说,达到了一种解耦的效果。内部子系统的任何变化都不会影响到门面模式接口的变化。
- 平面设计模式更注重从架构的层次去看整个系统,而不是单个类的层次。美面膜是很多时候更是一种架构设计模式。
- 平面设计模式并非一个集装箱可以任意的放进任何多个对象门面模式中组建的内部应该是相互和关系比较大的系列组件,而不是一个简单的功能集合。