C++设计模式_结构型模式_外观模式Facade
本文记录外观模式。
外观模式(Facade)又称为门面模式,是最简单的模式。该模式的作用是用来隔离接口,就是扮演中间层的角色,把结合紧密的两部分分割开,让这两部分内容通过中间层来打交道,类似于依赖倒置原则,高层和底层依赖于抽象层。从而极大的降低了两部分的耦合性。
一个配置相关的范例
一个游戏有如下配置:图形配置,声音配置和语音聊天配置,创建这三个类,因为这些类在项目中只保持一个对象即可,因此将这三个类设计为单例类。
class Graphic{private:Graphic() {};~Graphic() {};Graphic(const Graphic& ojb) {}Graphic& operator=(const Graphic& obj) {}public:static Graphic& getInstance(){static Graphic instance;return instance;}public:void displayFull(bool enable) // 显示全屏{cout << "displayFull" << endl;}void effect(bool enable) // 显示特效{cout << "effect" << enable << endl;}void resolution(int w, int h) //设置窗口分辨率{cout << "窗口分辨率宽:" << w << "分辨率高:" << h << endl;}void antialiasing(bool enable) // 抗锯齿{cout << "不开启抗锯齿 antialiasing" << endl;}};class Sound{public:Sound() {};~Sound() {};Sound(const Sound& ojb) {}Sound& operator=(const Sound& obj) {}public:static Sound& getInstance(){static Sound instance;return instance;}public:void volume(int v) // 设置音量{cout << "设置音量大小:" << v << endl;;}void setenvironmentVolume(int ev){cout << "开启环境音量 << " << ev << endl;}void setvolume(int v){cout << "设置音量大小为:" << v << endl;}};class chatVoice{private:chatVoice() {};~chatVoice() {};chatVoice(const chatVoice& ojb) {}chatVoice& operator=(const chatVoice& obj) {}public:static chatVoice& getInstance(){static chatVoice instance;return instance;}public:void setMicVoice(int v){cout << "设置麦克风音量" << v << endl;}void setMicSense(int s){cout << "设置麦克风灵敏度" << endl;}void setChatVolume(int c){cout << "聊天音量为 " << c << endl;}};void test(){Graphic& g1 = Graphic::getInstance();g1.displayFull(true);g1.effect(true);g1.antialiasing(true);g1.resolution(1920, 1080);Sound& s1 = Sound::getInstance();s1.setenvironmentVolume(100);s1.setvolume(100);s1.volume(100);chatVoice& c1 = chatVoice::getInstance();c1.setChatVolume(100);c1.setMicSense(100);c1.setMicVoice(111);/*displayFulleffect1不开启抗锯齿 antialiasing
窗口分辨率宽:1920分辨率高:1080
开启环境音量 << 100
设置音量大小为:100
设置音量大小:100
聊天音量为 100
设置麦克风灵敏度
设置麦克风音量111*/}
通过结果可以看出,达到了设计这些类的目的。
引入外观(facade)模式
上面的代码中,在void test()类中(由main函数调用)的上面两个类Graphic ,Sound类的接口称为客户端代码,把这些具体的类称为业务类;上边代码中的test()中体现了客户端代码和业务类代码的直接交互,这不是一种好的设计方法。
现在希望将业务类和客户端代码解耦,实现一个新类,扮演中间层的角色,客户端代码不在需要直接与业务类打交道,而是直接和中间类打交道,这个中间的类就是外观模式类,该类对客户端提供了一些简单的调用接口,客户端直接通过这些简单的接口达到调用业务类的目的,新的设计如下图所示:
外观模式强调的是一种程序设计思想,并不是一种特殊的编程手法。上面代码加了一个新类Façade类,实现了客户端代码和业务代码的解耦,代码设计如下:
class Graphic{private:Graphic() {};~Graphic() {};Graphic(const Graphic& ojb) {}Graphic& operator=(const Graphic& obj) {}public:static Graphic& getInstance(){static Graphic instance;return instance;}public:void displayFull(bool enable) // 显示全屏{cout << "displayFull" << endl;}void effect(bool enable) // 显示特效{cout << "effect" << enable << endl;}void resolution(int w, int h) //设置窗口分辨率{cout << "窗口分辨率宽:" << w << "分辨率高:" << h << endl;}void antialiasing(bool enable) // 抗锯齿{cout << "不开启抗锯齿 antialiasing" << endl;}};class Sound{public:Sound() {};~Sound() {};Sound(const Sound& ojb) {}Sound& operator=(const Sound& obj) {}public:static Sound& getInstance(){static Sound instance;return instance;}public:void volume(int v) // 设置音量{cout << "设置音量大小:" << v << endl;;}void setenvironmentVolume(int ev){cout << "开启环境音量 << " << ev << endl;}void setvolume(int v){cout << "设置音量大小为:" << v << endl;}};class chatVoice{private:chatVoice() {};~chatVoice() {};chatVoice(const chatVoice& ojb) {}chatVoice& operator=(const chatVoice& obj) {}public:static chatVoice& getInstance(){static chatVoice instance;return instance;}public:void setMicVoice(int v){cout << "设置麦克风音量" << v << endl;}void setMicSense(int s){cout << "设置麦克风灵敏度" << endl;}void setChatVolume(int c){cout << "聊天音量为 " << c << endl;}};class Facade{private:Facade() {};~Facade(){}Facade(const Facade& ojb) {}Facade& operator=(const Facade& obj) {}public:static Facade& getInstance(){static Facade instance;return instance;}public:// 定义一个高配置的方法void getHighConfig(){Graphic& g1 = Graphic::getInstance();g1.displayFull(true);g1.effect(true);g1.antialiasing(true);g1.resolution(1920, 1080);Sound& s1 = Sound::getInstance();s1.setenvironmentVolume(100);s1.setvolume(100);s1.volume(100);chatVoice& c1 = chatVoice::getInstance();c1.setChatVolume(100);c1.setMicSense(100);c1.setMicVoice(111);}void getLowConfig(){Graphic& g1 = Graphic::getInstance();g1.displayFull(false);g1.effect(false);g1.antialiasing(false);g1.resolution(1024, 180);Sound& s1 = Sound::getInstance();s1.setenvironmentVolume(10);s1.setvolume(10);s1.volume(10);chatVoice& c1 = chatVoice::getInstance();c1.setChatVolume(10);c1.setMicSense(10);c1.setMicVoice(11);}};// 定义一个低配置的方法 void test2(){Facade& f1 = Facade::getInstance();f1.getHighConfig();f1.getLowConfig();}
迪米特法则— 原则5
外观模式体现了面向对象程序设计的一个原则—迪米特原则,该原则如下:一个对象对其他对象的了解应该尽可能少,从而降低了对象之间的耦合,提高系统的可维护性。例如,在一个系统中,模块之间调用时,通过提供一个统一的接口来实现,这样其他模块就不需要了解另外一个模块内部的实现细节了,当一个模块内部发生改变时,也不会影响到其他模块。
外观模式有两种角色:
外观角色Façade ,客户端用Façade角色的方法,该方法将客户端的请求传递到业务类中。
子系统角色:子系统就是业务类 Graphic Sound chatVoice 类,这些子类被外观类调用。
外观模式定义:提供了一个统一的接口,用来访问子系统中的一群接口。
另一个外观模式的范例
下面的例子也是一个外观模式的例子,在这个例子中,Façade 是外观角色,其调用了其他的类的接口,实现了和客户端的解耦。
// Screen Light Speaker DvdPlayer PlayerStationclass Screen{public:void On(){cout << "打开屏幕" << endl;}void Off(){cout << "关闭屏幕" << endl;}};class Light{public:void On(){cout << "打开屏幕" << endl;}void Off(){cout << "关闭屏幕" << endl;}};class Speaker{public:void On(){cout << "打开屏幕" << endl;}void Off(){cout << "关闭屏幕" << endl;}};class Facade{public:void On(){
m_screen.On();
m_light.On();
m_speaker.On();}void Off(){
m_screen.Off();
m_light.Off();
m_speaker.Off();}private:Screen m_screen;Light m_light;Speaker m_speaker;};void test(){Facade f1;f1.On();f1.Off();}
UML图如下: