一、模式动机
当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观模式。外观模式(Facade-Pattern),之所以这么称呼,是因为它将一个或数个类的复杂一切都隐藏在背后,只显露出一个干净美好的外观。
二、模式定义
外观模式(Facade Pattern):提供了一个统一的接口,用来访问子系统中的一群接口。外观定义一个高层接口,让子系统更容易使用。
三、模式示例
你组装了一套杀手级的家庭影院系统,内含DVD播放器、投影仪、自动屏幕、环绕立体声,甚至还有爆米花。如下图所示:
但是观赏电影需要操作很多步,打开爆米花机,开始爆米花,将灯光调暗,放下屏幕,将投影机的输入切换到DVD…打开DVD播放器,开始播放DVD。现在用外观模式,一键搞定。
C++代码实现
#include <iostream>
#include <string>
using namespace std;
class TheaterLights
{
public:
TheaterLights();
~TheaterLights();
void on(){ cout << "Theater Lights On" << endl; }
void off(){ cout << "Theater Lights Off" << endl; }
void dim(int val){ cout << "Theater Lights Dim" << endl; }
private:
};
TheaterLights::TheaterLights()
{
}
TheaterLights::~TheaterLights()
{
}
class PopcomPopper
{
public:
PopcomPopper();
~PopcomPopper();
void on(){ cout << "PopcomPopper On" << endl; }
void off(){ cout << "PopcomPopper Off" << endl; }
void pop(){ cout << "PopcomPopper Pop" << endl; }
private:
};
PopcomPopper::PopcomPopper()
{
}
PopcomPopper::~PopcomPopper()
{
}
class Screen
{
public:
Screen();
~Screen();
void down(){ cout << "Screen Down" << endl; }
void up(){ cout << "Screen Up" << endl; }
private:
};
Screen::Screen()
{
}
Screen::~Screen()
{
}
class Amplifier;
class Tuner
{
public:
Tuner();
~Tuner();
void on(){ cout << "Tuner On" << endl; }
void off(){ cout << "Tuner Off" << endl; }
void setAmplifier(Amplifier* am) { amplifier = am; }
private:
Amplifier* amplifier;
};
Tuner::Tuner()
{
}
Tuner::~Tuner()
{
}
class CdPlayer
{
public:
CdPlayer();
~CdPlayer();
void on(){ cout << "CdPlayer On" << endl; }
void off(){ cout << "CdPlayer Off" << endl; }
void setAmplifier(Amplifier* am) { amplifier = am; }
private:
Amplifier* amplifier;
};
CdPlayer::CdPlayer()
{
}
CdPlayer::~CdPlayer()
{
}
class DvdPlayer
{
public:
DvdPlayer();
~DvdPlayer();
void on(){ cout << "DvdPlayer On" << endl; }
void off(){ cout << "DvdPlayer Off" << endl; }
void setAmplifier(Amplifier* am) { amplifier = am; }
private:
Amplifier* amplifier;
};
DvdPlayer::DvdPlayer()
{
}
DvdPlayer::~DvdPlayer()
{
}
class Projector
{
public:
Projector();
~Projector();
void on(){ cout << "DvdPlayer On" << endl; }
void off(){ cout << "DvdPlayer Off" << endl; }
void setDvdPlayer(DvdPlayer* player) { dvdPlayer = player; }
private:
DvdPlayer* dvdPlayer;
};
Projector::Projector()
{
}
Projector::~Projector()
{
}
class Amplifier
{
public:
Amplifier();
~Amplifier();
void on(){ cout << "Amplifier On" << endl; }
void off(){ cout << "Amplifier Off" << endl; }
void setDvdPlayer(DvdPlayer* player) { dvdPlayer = player; }
void setStereoSound(){ cout << "Amplifier Set StereoSound" << endl; }
void setVolume(int volume){ cout << "Amplifier Set Volume" << endl; }
private:
DvdPlayer* dvdPlayer;
};
Amplifier::Amplifier()
{
}
Amplifier::~Amplifier()
{
}
class HomeTheaterFacade
{
public:
HomeTheaterFacade(Amplifier* amp, Tuner* tuner, DvdPlayer* dvd, CdPlayer* cd, Projector* projector, TheaterLights* lights, PopcomPopper* poper);
~HomeTheaterFacade();
void watchMovie(string movie);
private:
Amplifier* amp;
Tuner* tuner;
DvdPlayer* dvd;
CdPlayer* cd;
Projector* projector;
TheaterLights* lights;
Screen* screen;
PopcomPopper* poper;
};
HomeTheaterFacade::HomeTheaterFacade(Amplifier* amp, Tuner* tuner, DvdPlayer* dvd, CdPlayer* cd, Projector* projector, TheaterLights* lights, PopcomPopper* poper)
:amp(amp),
tuner(tuner),
dvd(dvd),
cd(cd),
projector(projector),
lights(lights),
poper(poper)
{
}
HomeTheaterFacade::~HomeTheaterFacade()
{
}
void HomeTheaterFacade::watchMovie(string movie)
{
cout << "Get ready to watch " + movie << endl;
poper->on();
poper->pop();
lights->dim(10);
screen->down();
projector->on();
amp->on();
amp->setStereoSound();
amp->setVolume(5);
dvd->on();
}
int _tmain(int argc, _TCHAR* argv[])
{
TheaterLights* lights = new TheaterLights;
PopcomPopper* poper = new PopcomPopper;
Screen* screen = new Screen;
Tuner* tuner = new Tuner;
CdPlayer* cd = new CdPlayer;
DvdPlayer* dvd = new DvdPlayer;
Projector* projector = new Projector;
Amplifier* amp = new Amplifier;
projector->setDvdPlayer(dvd);
dvd->setAmplifier(amp);
cd->setAmplifier(amp);
tuner->setAmplifier(amp);
amp->setDvdPlayer(dvd);
HomeTheaterFacade homeTheater(amp, tuner, dvd, cd, projector, lights, poper);
homeTheater.watchMovie("1942");
system("pause");
return 0;
}
运行结果:
四、分析总结
外观模式将客户从一个复杂的子系统中解耦。实现一个外观,需要将子系统组合进外观中,然后将工作委托给子系统执行。
优点
- 实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可
- 只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类
缺点
- 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开放-关闭原则”。