This post implements facade design pattern in <Head First Design Patterns>. Facade pattern wrapps a complicated subsystem with a simpler interface. The general procedure
- Identify a simpler, unified interface for the subsystem or component.
- Design a “wrapper” class that encapsulates the subsystem.
- The facade/wrapper captures the complexity and collaborations of the component, and delegates to the appropriate methods.
- The client uses (is coupled to) the Façade only.
- Consider whether additional Facades would add value.
In the book, the whole system is complicated,
Facade pattern provides uniform and simple access to the system
The system component classes are given
class Amplifier {
private:
std::string description;
Tuner* tuner;
DvdPlayer* dvd;
CdPlayer* cd;
Amplifier(const Amplifier& ); // Disable copy constructor
void operator=(const Amplifier& ); // Disable assignment operator
public:
Amplifier(std::string description_): description(description_), tuner(0), dvd(0), cd(0){}
void on() const {
std::cout << description << " on" << std::endl;
}
void off() const {
std::cout << description << " off" << std::endl;
}
void setStereoSound() {
std::cout << description << " stereo mode on" << std::endl;
}
void setSurroundSound() {
std::cout << description << " surround sound on (5 speakers, 1 subwoofer)" << std::endl;
}
void setVolume(int level) {
std::cout << description << " setting volume to " << level << std::endl;
}
public: void setTuner(Tuner* tuner_) {
std::cout << description << " setting tuner to " << tuner->toString() << std::endl;
tuner = tuner_;
}
void setDvd(DvdPlayer* dvd_) {
std::cout << description << " setting DVD player to " << dvd->toString()<< std::endl;
dvd = dvd_;
}
void setCd(CdPlayer* cd_) {
std::cout << description << " setting CD player to " << cd->toString() << std::endl;
cd = cd_;
}
void toString() const {
return description.c_str();
}
};
class Tuner {
private:
std::string description;
Amplifier* amplifier;
double frequency;
Tuner(const Tuner& ); // Disable copy constructor
void operator=(const Tuner& ); // Disable assignment operator
public:
Tuner(std::string description_, Amplifier* amplifier_):description(description_), amplifier(amplifier_), frequency(0.0) {}
void on() {
std::cout << description.c_str() << " on" << std::endl;
}
void off() {
std::cout << description.c_str() << " off" << std::endl;
}
void setFrequency(double frequency_) {
std::cout << _description.c_str() << " setting frequency to " << _frequency << std::endl;
frequency = frequency_;
}
void setAm() {
std::cout << description.c_str() << " setting AM mode" << std::endl;
}
void setFm() {
std::cout << description.c_str() << " setting FM mode" << std::endl;
}
void toString() const {
return description;
}
};
class Screen {
private:
std::string description;
Screen(const Screen& ); // Disable copy constructor
void operator=(const Screen& ); // Disable assignment operator
public:
Screen(std::string description_ ):description(description_) {}
void up(){
std::cout << description.c_str() << " going up" << std::endl;
}
void down() {
std::cout << description.c_str() << " going down" << std::endl;
}
void toString() {
return description;
}
};
class PopcornPopper {
private:
std::string description;
PopcornPopper(const PopcornPopper& ); // Disable copy constructor
void operator=(const PopcornPopper& ); // Disable assignment operator
public:
PopcornPopper(std::string description_):description(description_){}
void on() const{
std::cout << description.c_str() << " on" << std::endl;
}
void off() const{
std::cout << description.c_str() << " off" << std::endl;
}
void pop() const{
std::cout << description.c_str() << " popping popcorn!" << std::endl;
}
void toString() const{
return description;
}
};
class TheaterLights {
private:
std::string description;
TheaterLights(const TheaterLights& ); // Disable copy constructor
void operator=(const TheaterLights& ); // Disable assignment operator
public:
TheaterLights(std::string description_):description(description_) {}
void on() {
std::cout << description.c_str() << " on" << std::endl;
}
void off() {
std::cout << description.c_str() << " off" << std::endl;
}
void dim(int level) {
std::cout << description.c_str() << " dimming to " << level << "%" << std::endl;
}
void toString() {
return description;
}
};
class CdPlayer {
private:
std::string description;
Amplifier* amplifier;
std::string title;
int currentTrack;
CdPlayer(const CdPlayer& ); // Disable copy constructor
void operator=(const CdPlayer& ); // Disable assignment operator
public:
CdPlayer(std::string description_, Amplifier* amplifier_):description(description_), amplifier(amplifier_), currentTrack_(0) {}
void on() const {
std::cout << description.c_str() << " on" << std::endl;
}
void off() const {
std::cout << description.c_str() << " off" << std::endl;
}
void eject() {
title.empty();
std::cout << description.c_str() << " eject" << std::endl;
}
void play(std::string title_) {
title = title_;
std::cout << description.c_str() << " playing \"" << _title << "\"" << std::endl;
}
void play(int track) {
if(title.length() == 0) {
std::cout << description.c_str() << " can't play track " << _currentTrack << ", no cd inserted" << std::endl;
} else {
currentTrack = track;
std::cout << description.c_str() << " playing track " << _currentTrack << std::endl;
}
}
void stop() {
currentTrack = 0;
std::cout << description.c_str() << " stopped" << std::endl;
}
void pause() {
std::cout << description.c_str() << " paused \"" << _title << "\"" << std::endl;
}
void toString() const {
return description;
}
};
class DvdPlayer {
private:
std::string description;
Amplifier* amplifier;
int currentTrack;
std::string movie;
DvdPlayer(const DvdPlayer& ); // Disable copy constructor
void operator=(const DvdPlayer& ); // Disable assignment operator
public:
DvdPlayer(std::string description_, Amplifier* amplifier_): description(description_), amplifier(amplifier_), currentTrack(0) {}
void on() const {
std::cout << description << " on" << std::endl;
}
void off() const {
std::cout << description << " off" << std::endl;
}
void eject() {
movie.empty();
std::cout << description << " eject" << std::endl;
}
void play(std::string movie_) {
movie = movie_;
std::cout << description << " playing \"" << movie << "\"" << std::endl;
}
void play(int track) {
if(movie.length() == 0) {
std::cout << description << " can't play track " << track << " no dvd inserted" << std::endl;
} else {
currentTrack = track;
std::cout << description << " playing track " << track << " of \"" << _movie << "\"" << std::endl;
}
}
void stop() {
currentTrack = 0;
std::cout << description << " stopped \"" << _movie << "\"" << std::endl;
}
public: void pause() {
std::cout << description << " paused \"" << _movie << "\"" << std::endl;
}
public: void setTwoChannelAudio() {
std::cout << description << " set two channel audio" << std::endl;
}
public: void setSurroundAudio() {
std::cout << description << " set surround audio" << std::endl;
}
public: std::string toString() const {
return description;
}
};
class Projector {
private:
std::string description;
DvdPlayer* dvdPlayer;
Projector(const Projector& ); // Disable copy constructor
void operator=(const Projector& ); // Disable assignment operator
public:
Projector(std::string description_, DvdPlayer* dvdPlayer_):description(description_), dvdPlayer(dvdPlayer_) {}
void on() {
std::cout << description.c_str() << " on" << std::endl;
}
void off() {
std::cout << description.c_str() << " off" << std::endl;
}
void wideScreenMode() {
std::cout << description.c_str() << " in widescreen mode (16x9 aspect ratio)" << std::endl;
}
void tvMode() {
std::cout << description.c_str() << " in tv mode (4x3 aspect ratio)" << std::endl;
}
void toString() {
return description;
}
};
The simplified interface is
class HomeTheaterFacade {
private:
Amplifier* amp;
Tuner* tuner;
DvdPlayer* dvd;
CdPlayer* cd;
Projector* projector;
TheaterLights* lights;
Screen* screen;
PopcornPopper* popper;
HomeTheaterFacade(const HomeTheaterFacade& ); // Disable copy constructor
void operator=(const HomeTheaterFacade& ); // Disable assignment operator
public:
HomeTheaterFacade(Amplifier* amp_, Tuner* tuner_, DvdPlayer* dvd_, CdPlayer* cd_, Projector* projector_, Screen* screen_, TheaterLights* lights_, PopcornPopper* popper_) :
amp(amp_), tuner(tuner_), dvd(dvd_), cd(cd_), projector(projector_), lights(lights_), screen(screen_), popper(popper_){}
void watchMovie(std::string movie_) {
std::cout << "Get ready to watch a movie..." << std::endl;
popper->on();
popper->pop();
lights->dim( 10 );
screen->down();
projector->on();
projector->wideScreenMode();
amp->on();
amp->setDvd( dvd );
amp->setSurroundSound();
amp->setVolume( 5 );
dvd->on();
dvd->play( movie_);
}
void endMovie() {
std::cout << "Shutting movie theater down..." << std::endl;
popper->off();
lights->on();
screen->up();
projector->off();
amp->off();
dvd->stop();
dvd->eject();
dvd->off();
}
void listenToCd( std::string cdTitle ) {
std::cout << "Get ready for an audiopile experence..." << std::endl;
lights->on();
amp->on();
amp->setVolume( 5 );
amp->setCd( cd );
amp->setStereoSound();
cd->on();
cd->play( cdTitle );
}
void endCd() {
std::cout << "Shutting down CD..." << std::endl;
amp->off();
amp->setCd( _cd );
cd->eject();
cd->off();
}
void listenToRadio( double frequency ) {
std::cout << "Tuning in the airwaves..." << std::endl;
tuner->on();
tuner->setFrequency( frequency );
amp->on();
amp->setVolume( 5 );
amp->setTuner( _tuner );
}
void endRadio() {
std::cout << "Shutting down the tuner..." << std::endl;
tuner->off();
amp->off();
}
};
Main function is
#include <iostream>
#include <./hometheater.hpp>
int main()
{
Amplifier* amp = new Amplifier("Top-O-Line Amplifier");
Tuner* tuner = new Tuner("Top-O-Line AM/FM Tuner", amp);
DvdPlayer* dvd = new DvdPlayer("Top-O-Line DVD Player", amp);
CdPlayer* cd = new CdPlayer("Top-O-Line CD Player", amp);
Projector* projector = new Projector("Top-O-Line Projector", dvd);
TheaterLights* lights = new TheaterLights("Theater Ceiling Lights");
Screen* screen = new Screen("Theater Screen");
PopcornPopper* popper = new PopcornPopper("Popcorn Popper");
HomeTheaterFacade* homeTheater = new HomeTheaterFacade(amp, tuner, dvd, cd, projector, screen, lights, popper);
homeTheater->watchMovie("Raiders of the Lost Ark");
homeTheater->endMovie();
return 0;
}