DesignPattern/11.FacadePattern/FacadePattern.md

5.8 KiB
Raw Blame History

如何吃到回锅肉?找厨师啊——外观模式实例解析

好不容易盼到周末啦Jungle想吃点好的犒劳自己吃什么呢回锅肉是的吃回锅肉
可是这过程好麻烦啊先得去市场里买肉买回来得洗好然后切好再炒肉最后才能吃上不仅过程繁杂而且Jungle还得跟市场、厨房打交道想想都头大。
如果有个厨师就好了Jungle直接告诉厨师“我要吃回锅肉”20分钟后厨师直接端上来就开吃。而中间那些买肉洗肉切肉的过程Jungle统统不关心了而且Jungle也不必再关心市场和厨房直接和厨师说句话就ok真是方便

avatar

在这个例子中厨师整合了一系列复杂的过程外界Jungle只需与厨师交互即可。在软件设计模式中有一类设计模式正式如此——外观模式。

1.外观模式简介

外观模式是一种使用频率较高的设计模式,它提供一个外观角色封装多个复杂的子系统,简化客户端与子系统之间的交互,方便客户端使用。外观模式可以降低系统的耦合度。如果没有外观类,不同的客户端在需要和多个不同的子系统交互,系统中将存在复杂的引用关系,如下图。引入了外观类,原有的复杂的引用关系都由外观类实现,不同的客户端只需要与外观类交互。

avatar

外观模式:
为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

外观模式的应用很多比如浏览器用户要查找什么东西不论是浏览知乎、腾讯或者CSDN用户都只需要打开浏览器即可剩下的搜索工作由浏览器完成。

2.外观模式结构

外观模式的UML结构图如下所示
avatar

外观模式一共有以下角色:

  • Facade外观角色:外观角色可以知道多个相关子系统的功能,它将所有从客户端发来的请求委派给相应的子系统,传递给相应的子系统处理。
  • SubSystem子系统角色:子系统是一个类,或者由多个类组成的类的集合,它实现子系统具体的功能。

3.外观模式代码实例

电脑主机Mainframe中只需要按下主机的开机按钮powerOn即可调用其他硬件设备和软件的启动方法如内存Memory的自检selfCheck、CPU的运行run、硬盘HardDisk的读取read、操作系统OS的载入load等。如果某一过程发生错误则电脑开机失败。

这里Jungle用外观模式来模拟该过程该例子UML图如下 avatar

3.1.子系统类

本例中一共有4个子系统因此设计4个类Memory、CPU、HardDisk和OS并且每个子系统都有自己独立的流程。

// subsystem: Memory
class Memory
{
public:
	Memory(){}
	void selfCheck(){
		printf("memory selfchecking......\n");
	}
};
 
// subsystem: CPU
class CPU
{
public:
	CPU(){}
	void run(){
		printf("running cpu......\n");
	}
};
 
// subsystem: hardDisk
class HardDisk
{
public:
	HardDisk(){}
	void read(){
		printf("reading hardDisk......\n");
	}
};
 
// subsystem: OS
class OS
{
public:
	OS(){}
	void load(){
		printf("loading os.....\n");
	}
};

3.2.外观类设计

class Facade
{
public:
	Facade(){
		memory = new Memory();
		cpu = new CPU();
		hardDisk = new HardDisk();
		os = new OS();
	}
	~Facade(){
		delete memory;
		delete cpu;
		delete hardDisk;
		delete os;
		memory = nullptr;
		cpu = nullptr;
		hardDisk = nullptr;
		os = nullptr;
	}
	Facade(const Facade& facade) = delete;
	Facade operator=(const Facade& facade) = delete;
	void powerOn(){
		printf("power on……\n");
		memory->selfCheck();
		cpu->run();
		hardDisk->read();
		os->load();
		printf("ready!\n");
	}
private:
	Memory *memory;
	CPU *cpu;
	HardDisk *hardDisk;
	OS *os;
};

3.3.客户端代码示例

#include <iostream>
#include "FacadePattern.h"
 
int main()
{
	Facade *facade = new Facade();
	facade->powerOn();
 
	printf("\n\n");
	delete facade;
	system("pause");
	return 0;
}

看到了吗,客户端的代码就是如此简单,跟子系统无关!

3.4.效果

avatar

4.总结

  • 优点:
    • 外观模式使得客户端不必关心子系统组件,减少了与客户端交互的对象的数量,简化了客户端的编程;
    • 外观模式可以大大降低系统的耦合度;
    • 子系统的变化并不需要修改客户端,只需要适当修改外观类即可;
    • 子系统之间不会相互影响。
  • 缺点:
    • 如果需要增加或者减少子系统,需要修改外观类,违反开闭原则;
    • 并不能限制客户端直接与子系统交互,但如果加强限制,又使得系统灵活度降低。
  • 适用场景:
    • 为访问一系列复杂的子系统提供一个统一的、简单的入口,可以使用外观模式;
    • 客户端与多个子系统之间存在很大依赖,但在客户端编程,又会增加系统耦合度,且使客户端编程复杂,可以使用外观模式。