1.场景分析
如下图所示,我们有一个家庭影院系统,其中包含了调音器、扩音器、播放器、剧场光、爆米花机等部分:
然后我们模拟使用这个系统来播放一部电影,则我们需要进行一下操作:
//打开爆米花机,开始爆米花
popper.on()
popper.pop()
//调灯光
lights.dim(10)
//把屏幕放下
screen.down()
//打开投影机
projector.on()
projector.setInput(dvd)
projector.wideScreenMode()
//设置音效
amp.on()
amp.setDvd(dvd)
amp.setSurroundSound()
amp.setVolume(5)
//打开DVD播放器播放电影
dvd.on()
dvd.play()
然后看完电影后,我们还需要把它们依次关掉。
从上面我们可以看出,使用这些子系统是十分繁琐的,这时我们就可以通过外观模式(Facade)来为一个复杂的子系统提供一个更合理、更简单易用的接口,如下
class HomeTheaterFacade
{
public:
HomeTheaterFacade(Amplifier *amp, Tuner *tuner, CdPlayer *cd, DvdPlayer *dvd, Projector *projector, TheaterLights *lights, Screen *screen, PopcornPopper *popper)
:_amp(amp), _tuner(tuner), _cd(cd), _dvd(dvd), _projector(projector), _lights(lights), _screen(screen), _popper(popper)
{
}
void watchMovie(const string& movie)
{
_popper->on()
_popper->pop()
_lights->dim(10)
_screen->down()
_projector->on()
_projector->setInput(dvd)
_projector->wideScreenMode()
_amp->on()
_amp->setDvd(dvd)
_amp->setSurroundSound()
_amp->setVolume(5)
_dvd->on()
_dvd->play()
}
void endMovie()
{
_popper->off();
_lights->off();
_screen->off();
_projector->off();
_amp->off();
_dvd->stop();
_dvd->off();
}
private:
Amplifier *_amp = nullptr;
Tuner *_tuner = nullptr;
CdPlayer *cd = nullptr;
DvdPlayer *_dvd = nullptr;
Projector *_projector = nullptr;
TheaterLights *_lights = nullptr;
Screen *_screen = nullptr;
PopcornPopper *_popper = nullptr;
};
2.意图
为一个子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
3.适用性
- 当你需要为一个复杂的子系统提供一个简单的接口的时候。
- 客户端与抽象类的实现之间存在很大的依赖性,引入Facade将这个子系统与客户端以及其他子系统分离,可以提高子系统的独立性与可移植性。
- 如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化它们之间的依赖关系。
4.结构
Facade模式通常配合很多子系统一起使用。
5.效果
1> 它对客户屏蔽了子系统组件,因而减少了客户处理对象的数目并使得子系统实用起来更加方便。
2> 它实现了子系统与客户之间的松耦合关系,而子系统内部往往是紧耦合的。在大型软件系统中降低编译依赖性至关重要,在子系统改变时,希望尽量减少重编译时间以节省时间,而Facade模式可以降低编译依赖性。
3>如果客户需要,它并不限制客户直接使用子系统。
6.实现
1> 降低客户-子系统之间的耦合度。用抽象类实现Facade,而它的具体子类对应于不同的子类系统,这可以进一步降低客户与子系统的耦合度。