//+------------------------------------------------------------------+ //| Facade.mqh | //| 2019-2020, dimitri pecheritsa | //| 792112@gmail.com | //+------------------------------------------------------------------+ //| facade > structural design pattern | //+------------------------------------------------------------------+ // design patterns: elements of reusable object-oriented software // gof > erich gamma, richard helm, ralph johnson, john vlissides // published > 1994 //+------------------------------------------------------------------+ //| intent | //+------------------------------------------------------------------+ // provide a unified interface to a set of interfaces in a subsystem // facade defines a higher-level interface that makes the subsystem // easier to use //+------------------------------------------------------------------+ //| applicability | //+------------------------------------------------------------------+ // you want to provide a simple interface to a complex subsystem // subsystems often get more complex as they evolve // most patterns, when applied, result in more and smaller classes // this makes the subsystem more reusable and easier to customize, // but it also becomes harder to use for clients that don't need to // customize it // a facade can provide a simple default view of the subsystem // that is good enough for most clients // only clients needing more customizability will need to look // beyond the facade // there are many dependencies between clients and the implementation // classes of an abstraction // introduce a facade to decouple the subsystem from clients and // other subsystems, thereby promoting subsystem independence // and portability // you want to layer your subsystems // use a facade to define an entry point to each subsystem level // if subsystems are dependent, then you can simplify the // dependencies between them by making them communicate // with each other solely through their facades //+------------------------------------------------------------------+ //| structure | //+------------------------------------------------------------------+ // // +---------------------------|facade|-------------------------+ // | subsystem classes | | // | | | // | ------- ------- | -------- | // | | |--+ | |<------+ | | | // | ------- | ------- | -------- | // | ^ | | ^ | // | | | ------- | | | // | | +-----| |<---+ +-----+-----+ | // | | ------- | | | | // | ------- | -------- -------- | // | | |<--------------------+--->| | | | | // | ------- -------- -------- | // | | // +------------------------------------------------------------+ // #include <SRCPatternsPatternOrganizer.mqh> namespace Facade { //+------------------------------------------------------------------+ //| participants > subsystem classes | //+------------------------------------------------------------------+ // implement subsystem functionality // handle work assigned by the facade object // have no knowledge of the facade — keep no references to it //+------------------------------------------------------------------+ //| participants > subsystem classes > subsystem a | //+------------------------------------------------------------------+ class SubSystemA { public: void Operation(void); }; //+------------------------------------------------------------------+ //| participants > subsystem classes > subsystem a > opereation | //+------------------------------------------------------------------+ void SubSystemA::Operation(void) { Print("subsystem a > operation"); } //+------------------------------------------------------------------+ //| participants > subsystem classes > subsystem b | //+------------------------------------------------------------------+ class SubSystemB { public: void Operation(void); }; //+------------------------------------------------------------------+ //| participants > subsystem classes > subsystem b > opereation | //+------------------------------------------------------------------+ void SubSystemB::Operation(void) { Print("subsystem b > operation"); } //+------------------------------------------------------------------+ //| participants > subsystem classes > subsystem c | //+------------------------------------------------------------------+ class SubSystemC { public: void Operation(void); }; //+------------------------------------------------------------------+ //| participants > subsystem classes > subsystem c > opereation | //+------------------------------------------------------------------+ void SubSystemC::Operation(void) { Print("subsystem c > operation"); } //+------------------------------------------------------------------+ //| participants > facade | //+------------------------------------------------------------------+ class Facade // knows which subsystem classes are responsible for a request // delegates client requests to appropriate subsystem objects { public: void OperationAB(void); void OperationBC(void); protected: SubSystemA subsystem_a; SubSystemB subsystem_b; SubSystemC subsystem_c; }; //+------------------------------------------------------------------+ //| participants > facade > operation a—b | //+------------------------------------------------------------------+ void Facade::OperationAB(void) { Print("facade > operation a & b"); Print("facade > requesting > subsystem a > operation"); subsystem_a.Operation(); Print("facade > requesting > subsystem b > operation"); subsystem_b.Operation(); } //+------------------------------------------------------------------+ //| participants > facade > operation b—c | //+------------------------------------------------------------------+ void Facade::OperationBC(void) { Print("facade > operation b & c"); Print("facade > requesting > subsystem b > operation"); subsystem_b.Operation(); Print("facade > requesting > subsystem c > operation"); subsystem_c.Operation(); } //+------------------------------------------------------------------+ //| participants > client | //+------------------------------------------------------------------+ class Client:public ClientExample { public: string Output(void); void Run(void); }; string Client::Output(void) { return __FUNCTION__; } //+------------------------------------------------------------------+ //| collaborations | //+------------------------------------------------------------------+ void Client::Run(void) // clients communicate with the subsystem by sending requests to facade // which forwards them to the appropriate subsystem object(s) // although the subsystem objects perform the actual work, // the facade may have to do work of its own to translate its // interface to subsystem interfaces // clients that use the facade don't have to access its subsystem // objects directly { Facade facade; Print("client > requesting > facade operation a & b"); facade.OperationAB(); Print("client > requesting > facade operation b & c"); facade.OperationBC(); } } //+------------------------------------------------------------------+ //| output | //+------------------------------------------------------------------+ // Facade::Client::Output // client > requesting > facade operation a & b // facade > operation a & b // facade > requesting > subsystem a > operation // subsystem a > operation // facade > requesting > subsystem b > operation // subsystem b > operation // client > requesting > facade operation b & c // facade > operation b & c // facade > requesting > subsystem b > operation // subsystem b > operation // facade > requesting > subsystem c > operation // subsystem c > operation //+------------------------------------------------------------------+ //| consequences | //+------------------------------------------------------------------+ // it shields clients from subsystem components, // thereby reducing the number of objects that clients deal with // and making the subsystem easier to use // it promotes weak coupling between the subsystem and its clients // often the components in a subsystem are strongly coupled // weak coupling lets you vary the components of the subsystem // without affecting its clients // facades help layer a system and the dependencies between objects // they can eliminate complex or circular dependencies // this can be an important consequence when the client // and the subsystem are implemented independently // reducing compilation dependencies is vital in large software systems // you want to save time by minimizing recompilation when // subsystem classes change // reducing compilation dependencies with facades can limit the // recompilation needed for a small change in an important subsystem // a facade can also simplify porting systems to other platforms, // because it's less likely that building one subsystem requires // building all others // it doesn't prevent applications from using subsystem classes // if they need to // thus you can choose between ease of use and generality //+------------------------------------------------------------------+ //| implementation | //+------------------------------------------------------------------+ // reducing client-subsystem coupling // the coupling between clients and the subsystem can be reduced // even further by making facade an abstract class with // concrete subclasses for different implementations of a subsystem // then clients can communicate with the subsystem through the // interface of the abstract facade class // this abstract coupling keeps clients from knowing which // implementation of a subsystem is used // an alternative to subclassing is to configure a facade object // with different subsystem objects // to customize the facade, simply replace one or more of its // subsystem objects // public versus private subsystem classes // a subsystem is analogous to a class in that both have interfaces, // and both encapsulate something—a class encapsulates state // and operations, while a subsystem encapsulates classes // and just as it's useful to think of the public and private // interface of a class, we can think of the public and private // interface of a subsystem // the public interface to a subsystem consists of classes that // all clients can access // the private interface is just for subsystem extenders // the facade class is part of the public interface, of course, // but it's not the only part // other subsystem classes are usually public as well //+------------------------------------------------------------------+ //| related patterns | //+------------------------------------------------------------------+ // abstract factory // can be used with facade to provide an interface for creating // subsystem objects in a subsystem-independent way // abstract factory can also be used as an alternative to facade // to hide platform-specific classes // mediator // is similar to facade in that it abstracts functionality of // existing classes // however, mediator's purpose is to abstract arbitrary // communication between colleague objects, often centralizing // functionality that doesn't belong in any one of them // mediator's colleagues are aware of and communicate with the // mediator instead of communicating with each other directly // in contrast, a facade merely abstracts the interface to // subsystem objects to make them easier to use // it doesn't define new functionality, and subsystem // classes don't know about it // singleton // usually only one facade object is required // thus facade objects are often singletons //+------------------------------------------------------------------+