假设你必须在代码中使用某个复杂的库或框架中的众多对象。 正常情况下, 你需要负责所有对象的初始化工作、 管理其依赖关系并按正确的顺序执行方法等。
最终, 程序中类的业务逻辑将与第三方类的实现细节紧密耦合, 使得理解和维护代码的工作很难进行。
如果你的程序需要与包含几十种功能的复杂库整合, 但只需使用其中非常少的功能, 那么使用外观模式会非常方便,
例如, 上传猫咪搞笑短视频到社交媒体网站的应用可能会用到专业的视频转换库, 但它只需使用一个包含encode(filename, format)
方法 (以文件名与文件格式为参数进行编码的方法) 的类即可。 在创建这个类并将其连接到视频转换库后, 你就拥有了自己的第一个门面。
(1)模式动机
上述A方案的问题在于组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战。
如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系统的变化之间的依赖相互解耦?
(2)模式定义
为子系统中的一组接口提供一个一致(稳定)的界面,Facade模式定义了一个高层接口,这个接口使得这—子系统更加容易使用(复用)。
(3)要点总结
a). 从客户程序的角度来看,Facade模式简化了整个组件系统的接口,对于组件内部与外部客户程序来说,达到了一种“解耦”的效果——内部子系统的任何变化不会影响到Facade接口的变化。
b). Facade设计模式更注重从架构的层次去看整个系统,而不是单个类的层次。Facade很多时候更是一种架构设计模式。
c). Facade设计模式并非一个集装箱,可以任意地放进任何多个对象。Facade模式中组件的内部应该是“相互耦合关系比较大的一系列组件”,而不是一个简单的功能集合。
/**
* 子系统可以直接从门面或客户端接受请求
* 无论如何,对于子系统来说,Facade是另一个客户端,但它不是子系统的一部分
*/
class Subsystem1 {
public:
std::string Operation1() const {
return "Subsystem1: Ready!\n";
}
// ...
std::string OperationN() const {
return "Subsystem1: Go!\n";
}
};
/**
* 有些 Facade(门面) 可以同时使用多个子系统。
*/
class Subsystem2 {
public:
string Operation1() const {
return "Subsystem2: Get ready!\n";
}
// ...
string OperationZ() const {
return "Subsystem2: Fire!\n";
}
};
/**
* Facade类为一个或多个子系统的复杂逻辑提供了一个简单的接口
* Facade将客户端请求委托给子系统中的适当对象
* Facade还负责管理它们的生命周期
* 所有这些都使客户端避免了子系统的不必要的复杂性
*/
class Facade {
protected:
Subsystem1 *subsystem1_;
Subsystem2 *subsystem2_;
public:
/**
* 根据你的应用程序的需要,你可以为Facade提供现有的子系统对象,或者强制Facade自己创建它们
*/
Facade(
Subsystem1 *subsystem1 = nullptr,
Subsystem2 *subsystem2 = nullptr) {
this->subsystem1_ = subsystem1 ?: new Subsystem1;
this->subsystem2_ = subsystem2 ?: new Subsystem2;
}
~Facade() {
delete subsystem1_;
delete subsystem2_;
}
/**
* Facade的方法是子系统复杂功能的便捷快捷方式
* 然而,客户端只能获得子系统功能的一小部分。
*/
string Operation() {
string result = "Facade initializes subsystems:\n";
result += this->subsystem1_->Operation1();
result += this->subsystem2_->Operation1();
result += "Facade orders subsystems to perform the action:\n";
result += this->subsystem1_->OperationN();
result += this->subsystem2_->OperationZ();
return result;
}
};
/**
* 客户端通过Facade提供的简单接口与复杂的子系统一起工作
* 当Facade管理子系统的生命周期时,客户端甚至可能不知道子系统的存在,这种方法使您能够控制复杂性
*/
void ClientCode(Facade *facade) {
// ...
std::cout << facade->Operation();
// ...
}
/**
* 客户端代码可能已经创建了子系统的一些对象
* 在这种情况下,用这些对象初始化Facade而不是让Facade创建新的实例会更好
*/
int main() {
Subsystem1 *subsystem1 = new Subsystem1;
Subsystem2 *subsystem2 = new Subsystem2;
Facade *facade = new Facade(subsystem1, subsystem2);
ClientCode(facade);
delete facade;
return 0;
}