Facade Design Pattern in C#
Mani Bhushan Shukla
Technology-neutral Architect experienced in Product Engineering, C#, Azure, AWS, Microservices, and Multitenant Applications. Specializes in Scalability, Digital Innovation, Cyber Security, and AI & ML.
The design patterns act as reusable solutions to commonly occurring problems. One such pattern is the Facade Design Pattern. As the name suggests, this pattern provides a simplified and unified interface to a complex system, making it easier to use and understand. By encapsulating the underlying complexity, the Facade pattern promotes loose coupling, enhances maintainability, and improves code readability.
The Facade Design Pattern is categorized as a?Structural Design Pattern. According to the definition provided by the Gang of Four (GoF):
"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."
The main purpose of the Facade pattern is to improve the usability and maintainability of a system by reducing dependencies and providing a higher-level interface. It encapsulates a group of interfaces, classes, or subsystems and presents a simplified interface that hides the underlying implementation details.
To illustrate this, consider the process of shipping a product from an online shopping store involves several complex steps, such as inventory updates, address verification, credit card validation, applying discounts, and more. Each of these steps can be considered a subsystem within the larger online ordering system. To simplify the process, we can apply the Facade pattern.
In this scenario, we create a Facade object that acts as an interface for the subsystems involved: InventoryUpdate, AddressVerification, Discounting, PayCardVerification, and Shipping. Instead of directly calling each subsystem from the client code, we can call a single operation, such as "FinalizeOrder," on the Facade object. This operation, in turn, handles the coordination and invocation of the underlying subsystems.
领英推荐
Without the Facade pattern, the client code would need to create separate objects for each subsystem and call their respective operations. This approach can quickly become messy and cluttered. This approach keeps the client code clean and prevents pollution. The Facade object acts as a central point of interaction, making the subsystems easier to use and maintain.
An example of the?Facade Design Pattern in C#:
// Sub-system for inventory management
interface IInventory
{
void Update(int productId);
}
class InventoryManager:IInventory
{
public void Update(int productId)
{
Console.WriteLine(string.Format("Product# {0} is subtracted from the store's
inventory." , productId));
}
}
// Sub-system for order verification
interface IOrderVerify
{
bool VerifyShippingAddress(int pincode);
}
class OrderVerificationManager:IOrderVerify
{
public bool VerifyShippingAddress(int pincode)
{
Console.WriteLine(string.Format("The product can be shipped to the pincode {0}.",
pincode));
return true;
}
}
// Sub-system for discounts and costing.
interface ICosting
{
float ApplyDiscounts(float price,float discountPercent);
}
class CostManager:ICosting
{
public float ApplyDiscounts(float price,float discountPercent)
{
Console.WriteLine(string.Format("A discount of {0}% has been applied on the product's
price of {1}", discountPercent,price));
return price - ((discountPercent / 100) * price);
}
}
// Sub-system for payment gateway.
interface IPaymentGateway
{
bool VerifyCardDetails(string cardNo);
bool ProcessPayment(string cardNo, float cost);
}
class PaymentGatewayManager:IPaymentGateway
{
public bool VerifyCardDetails(string cardNo)
{
Console.WriteLine(string.Format("Card# {0} has been verified and is accepted.",
cardNo));
return true;
}
public bool ProcessPayment(string cardNo, float cost)
{
Console.WriteLine(string.Format("Card# {0} is used to make a payment of
{1}.",cardNo,cost));
return true;
}
}
// Sub-system for Logistics.
interface ILogistics
{
void ShipProduct(string productName, string shippingAddress);
}
class LogisticsManager:ILogistics
{
public void ShipProduct(string productName, string shippingAddress)
{
Console.WriteLine(string.Format("Congratulations your product {0} has been shipped
at the following address: {1}", productName, shippingAddress));
}
}
// The facade object.
class OnlineShoppingFacade
{
IInventory inventory = new InventoryManager();
IOrderVerify orderVerify = new OrderVerificationManager();
ICosting costManger = new CostManager();
IPaymentGateway paymentGateWay = new PaymentGatewayManager();
ILogistics logistics = new LogisticsManager();
public void FinalizeOrder(OrderDetails orderDetails)
{
inventory.Update(orderDetails.ProductNo);
orderVerify.VerifyShippingAddress(orderDetails.PinCode);
orderDetails.Price = costManger.ApplyDiscounts(orderDetails.Price,
orderDetails.DiscountPercent);
paymentGateWay.VerifyCardDetails(orderDetails.CardNo);
paymentGateWay.ProcessPayment(orderDetails.CardNo, orderDetails.Price);
logistics.ShipProduct(orderDetails.ProductName, string.Format("{0}, {1} - {2}.",
orderDetails.AddressLine1, orderDetails.AddressLine2, orderDetails.PinCode));
}
}
// So the facade object has exposed us a method “FinalizeOrder”
// through which all the methods of the various sub-systems are called.
// Let’s look at the client code which would be using this facade
// object to call the sub-systems
static void Main(string[] args)
{
// Creating the Order/Product details
OrderDetails orderDetails = new OrderDetails("C# Design Pattern Book",
"Simplified book on design patterns in C#",500,10,"Street No 1",
"Educational Area",1212,"4156213754");
// Using Facade
OnlineShoppingFacade facade = new OnlineShoppingFacade();
facade.FinalizeOrder(orderDetails);
Console.ReadLine();
}
I hope this is helpful!!
Wishing you a wonderful day ahead!!