Facade is an object that provides common access point to the application class library; it is accessible for large set of application objects through well designed API with convenient methods.
When designing a large system with many classes that are spread across many packages it's often make sense to design a facade that is accessible to all application objects and through which application objects from different packages can be accessed.
In client-server applications Remote Facade is used to minimize the number of remote calls; with the Remote Facade pattern client interacts with coarse-grained server object (called Remote Facade) that translates coarse-grained methods onto the underlying fine-grained objects.
This post walks through several implementations of the facade pattern and offers solutions for common dilemmas that raise during the implementation of the facade.
Singleton Facade - Tightly Coupled
The most common facade is a singleton object that acts as the main access point of the application through which the main objects (managers, controllers etc) can be accessed and common operations can be executed. Such facade is often responsible for instantiating and initializing the main objects and getting the application up and running.
The following facade manages three table module objects and one plug-in object, it creates the objects upon initialization (via LoadSystem) and exposes their interfaces to its clients. It also provides function to easily pull out the orders of a given customer from the data source.
Since the facade is supposed to be accessible to almost every application object - it will be best if it will reside in a common component (dll) that has as few dependencies as possible. However, since the facade object instantiate the types that it's exposes it's due to depend on components from all across the system.
The problem with this facade is that in order to instantiate and initialize the table modules and the plug-in object its component includes the Markrt.Core and the Market.Plugin components, consequently, the facade users (Client1 and Client2) also indirectly include the latter components which is obviously a problem.
Another problem is that the facade core components (Market.Core and Market.PlugIn) cannot use the facade in order to interact with each other (due to circular reference). For example, CustomerTableModule (from Market.Core) cannot use ReportManager (from Market.PlugIn) through the facade.
The good thing about the this facade is that it's simple. In small applications its often make sense to keep it simple and live with a little tightly coupled facade, though it can work only incase the facade has few clients and its underlying objects don't have to interact with each other.
Singleton Facade - Loosely Coupled
In order to solve the dependencies problem of the latter facade we should come out with a loosely coupled facade that doesn't depend on "core" component such as Markrt.Core and Market.Plugin.
The obvious place for such facade is in the Market.Common package that is reachable though all across the system and doesn't dependent on other components.
The problem is that once the facade is moved to the Market.Common package it cannot instantiate the main objects of the system (via LoadSystem) any more, in order to solve this problem we'll change the scope of the MiniMarketFacade internal fields (m_Customers, m_Orders etc) from private to protected, add new class called 'MiniMarketFacadeImp' that inherits from MiniMarketFacade, and move the LoadSystem implementation from MiniMarketFacade to the new MiniMarketFacadeImp class. Now, MiniMarketFacadeImp will instantiate the main objects and populate MiniMarketFacade protected fields.
Indeed, separating the facade into two classes that reside in different components will make it a little more complex, but large systems cannot afford tightly coupled facade so we really don't have much of a choice.
Placing the facade in Market.Common turned out to be a great move that certainly worth the effort. The facade clients are not forced to include the core components, they depend only on Market.Common component. The core components (Market.Core and Market.Plugin) can now use the facade in order to interact with each other.
Hi Aviad,
ReplyDeleteThe problem that I see here is that clients of the Facade are dependent on an implementation instead of a contract.
The best solution IMO is to use a single-instance (not singleton) facade that implements an interface, and have the clients accept the dependency (i.e through their constructor as in dependency injection/inversion of control).
That way you won't need to split your implementation, and still have a loosely-coupled
facade.
Hi Omer, Thanks for the comment.
ReplyDeleteI agree that in very large systems singleton facade (or singleton at all) is not such a good idea and it makes more sense to inject the facade interface rather than call its implementation. However, IMO, large applications with fairly strict bounds can make good use of the singleton pattern (it is not always an anti pattern…), this post shows how one can save the effort of injecting the facade to every application object and still keep the latter’s loosed.
IoC (Inversion of control) addicts such as yourself got used to working with IoC container - and just can’t see why sometimes it is not so comfortable to ‘manually’ inject the facade to almost every object in the system…
You're using the facade as a ServiceLocator?
ReplyDelete