Understanding the Facade design pattern in C#
In this post we are going to work through another common type of Structural Pattern called as Facade. In laymen terms Facade pattern is used to provide a simple interface for a rather complex system.
The Problem
At times in our system which has n number of subsystems and modules, there exist close requirement to interact with third party applications to retrieve, store or share data.
For a poorly designed system, the client will need to know great details such as data formats, service url's, metadata, invocation protocols, response type and so on.
The Solution: Facade
In such cases it would be logical to have a common system which provides an abstraction to all these third party services. This system would be responsible for the interactions and would act as a gateway for the client to communicate with them without actually getting involved into the complexity of the system.
As in the representation above, the client actually wants to communicate with three external subsystems Operation1(), Operation2() & Operation3(). The Facade acts as a middleware providing a uniform an simplified endpoint to get this job done.
All 3 subsystem can be totally different from each other, they may require different protocol for accessibility, but for the client all those details are hidden. No matter which subsystem the client wants to interact with, their is a simple consistent way of doing it
Implementation
Consider we want to develop a social plugin which allows user to input an item and the service gets its price from all popular e-commerce portals.
Facade pattern can be really very useful here, otherwise the client application will be overwhelmed by the complexity of setting up calls to all different portal available.
- Let us assume that there are three external services which when called with the product ID return the current price.
GetPriceByIDFromAmazon(int productId)
GetPriceByIDFromFlipkart(int productISIN)
GetPriceByIDFromBestBuy(int shopItem)
- The actual implementation of these three services are not known to us as they are external its just we need to set up the communication system with them and pass on the product identifier correctly to retrieve the price.
- PriceAccumalator class will act as our Facade, accepting product identifier from the client and returning a list of prices from all available partner vendors.
- The client here doesn't need to know about the existence of subsystem. For it calling the PriceAccumator should do the trick
public class PriceAccumalatedDetails { public int ProductId { get; set; } public List<PriceDetails> PriceDetails { get; set; } } public class PriceDetails { public decimal CurrentPrice { get; set; } public bool InStock { get; set; } public int VendorId {get;set;} public string VendorName {get;set;}
public string ProductLink {get;set;}
}
PriceAccumalatedDetails is response model the client would be expecting after it requests the pricing details of the product. This response will contain the product details and list of object with pricing details mapped for each vendor.
Below could be the sample classes which actually communicates with the third party systems
public class AmazonService { public AmazonService() { } public PriceDetails GetPriceByIDFromAmazon(int productId){
}
}
public class FlipkartService { public FlipkartService() { } public PriceDetails GetPriceByIDFromFlipkart(int productISIN){
}
}
public class BestBuyService { public BestBuyService() { } public PriceDetails GetPriceByIDFromBestBuy(int shopItem){
}
}
- Let us now build our Facade class PriceAccumalator which calls these three services internally to get the price from each of them
public class PriceAccumalator { public PriceAccumalatedDetails GetPriceFromVendors(int productId){ List<PriceDetails> accumalatedPrice = new List<PriceDetails>(); AmazonService amazon = new AmazonService(); accumalatedPrice.Add(amazon.GetPriceByIDFromAmazon(productId)); FlipkartService flipkart = new FlipkartService(); accumalatedPrice.Add(flipkart.GetPriceByIDFromFlipkart(productId)); BestBuyService bestBuy = new BestBuyService(); accumalatedPrice.Add(amazon.GetPriceByIDFromBestBuy(productId)); return new PriceAccumalatedDetails() {
productId = productId,
PriceDetails = accumalatedPrice
};
}
}
So, now the client just needs to be aware about the PriceAccumulator which does fulfil its requirement. This implementation also allows addition of new vendor without involving any change from the client side.
As always thanks for giving your time to my content and I hope it was useful. Till next time, keep learning & keep building.