Facade Design Pattern Real World Example in C#

Last Updated: 2023-12-24 14:16:32

The facade design pattern is a structural design pattern that gives a simplified way to use a system by hiding its internal complexity. In this post, I will try to explain the Facade design pattern from a very high level with a real-world example. I will provide you with the complete source code so that you can customize the code and get a better idea about the facade pattern.

For your information, in our previous post, we explained the Adapter Design pattern in C# with a real-world example. You can check that post too for learning design patterns.

 

What is the Facade Design pattern?

A structural design pattern that provides a simplified way(interface) to access(use) a complex system by hiding its internal complexity. It allows clients to interact with a system through a unified and straightforward interface, hiding the underlying complexities of the system.

 

 

A real-world example of the Facade Design Pattern

Imagine a husband (let's call him John) and his wife (let's call her Jane). John loves to eat delicious and diverse meals, so he frequently buys groceries from the market. However, he doesn't know much about cooking and the complexities involved in preparing those meals.

Jane, on the other hand, is an excellent cook and enjoys experimenting with various recipes. She knows the intricacies of cooking, the right ingredients, cooking times, and techniques required to create delightful dishes.

In this scenario, Jane plays the role of the "facade" in software engineering terms. She acts as the intermediary between John (the client) and the complex subsystem (cooking process). Here's how the analogy works:

  1. John (Client): John is the client who desires to have delicious meals regularly. He doesn't want to deal with the complexities of cooking, but he loves to eat different types of dishes.
  2. Jane (Facade): Jane is like the facade in the software engineering context. She simplifies the cooking process for John by providing a unified interface. John doesn't need to know the intricacies of cooking; he can just request the type of meal he wants, and Jane takes care of the rest.
  3. Cooking Subsystem: The cooking subsystem represents the complex processes involved in preparing various meals. It includes tasks like chopping vegetables, marinating meats, using different cooking techniques, and managing cooking times.

 

 

Please note that if you want a technical example please see our E-commerce Shopping Cart Example of Facade Design Pattern.

 

 

So, when John wants to eat something, he communicates his food preferences to Jane, the facade. For example, he might say, "Jane, I'm in the mood for a delicious pasta dish tonight." Jane takes this request and interacts with the cooking subsystem (cooking process) to prepare the pasta exactly the way John likes it, with the appropriate ingredients, seasonings, and cooking methods. John enjoys his tasty pasta without worrying about the details of the cooking process.

 

In this analogy, the facade pattern helps John (the client) interact with the cooking subsystem (complex processes) through a simplified and easy-to-use interface (Jane, the wife). The facade (Jane) abstracts away the complexities of cooking and provides a convenient way for John to get his desired meals without needing to understand or deal with the intricacies of the cooking process.

 

using System;

// Cooking Subsystem
public class CookingSubsystem
{
    public void CookPasta()
    {
        Console.WriteLine("Cooking pasta: Boil water, add pasta, and simmer until al dente.");
    }

    public void GrillChicken()
    {
        Console.WriteLine("Grilling chicken: Marinate chicken and grill until fully cooked.");
    }

    public void StirFryVegetables()
    {
        Console.WriteLine("Stir-frying vegetables: Chop vegetables and stir-fry in a hot pan.");
    }

    public void BakeCake()
    {
        Console.WriteLine("Baking cake: Mix ingredients and bake in the oven.");
    }

    public void MakeSandwich()
    {
        Console.WriteLine("Making sandwich: Assemble bread, cheese, and vegetables.");
    }

    public void PrepareSalad()
    {
        Console.WriteLine("Preparing salad: Wash and chop fresh vegetables.");
    }
}

// Wife (Facade) Class
public class Wife
{
    private CookingSubsystem cookingSubsystem;

    public Wife()
    {
        cookingSubsystem = new CookingSubsystem();
    }

    public void PrepareBreakfast(string[] ingredients)
    {
        Console.WriteLine("Wife: Preparing breakfast for husband.");
        cookingSubsystem.MakeSandwich();
        cookingSubsystem.PrepareSalad();
        Console.WriteLine("Wife: Breakfast is ready!");
    }

    public void PrepareLunch(string mainDish, string[] sideDishes)
    {
        Console.WriteLine("Wife: Preparing lunch for husband.");
        Console.WriteLine("Main Dish: " + mainDish);
        foreach (var sideDish in sideDishes)
        {
            Console.WriteLine("Side Dish: " + sideDish);
        }
        Console.WriteLine("Wife: Lunch is ready!");
    }

    public void PrepareDinner(string pastaType, string chickenType, string[] vegetables, string cakeType)
    {
        Console.WriteLine("Wife: Preparing dinner for husband.");
        cookingSubsystem.CookPasta();
        cookingSubsystem.GrillChicken();
        cookingSubsystem.StirFryVegetables();
        cookingSubsystem.BakeCake();
        Console.WriteLine("Wife: Dinner is ready!");
    }
}

// Husband (Main Program)
public class Husband
{
    public static void Main(string[] args)
    {
        Wife wife = new Wife();
        
        // Breakfast
        string[] breakfastIngredients = { "bread", "cheese", "lettuce", "tomato" };
        wife.PrepareBreakfast(breakfastIngredients);

        // Lunch
        string mainDish = "Baked Salmon";
        string[] sideDishes = { "Steamed Broccoli", "Mashed Potatoes" };
        wife.PrepareLunch(mainDish, sideDishes);

        // Dinner
        string pastaType = "spaghetti";
        string chickenType = "grilled";
        string[] vegetables = { "carrots", "broccoli", "bell peppers" };
        string cakeType = "chocolate";
        wife.PrepareDinner(pastaType, chickenType, vegetables, cakeType);
    }
}


In this example, we have three classes: CookingSubsystem, Wife, and Husband.

  1. CookingSubsystem: This class represents the cooking tasks or processes that the wife (facade) can coordinate to prepare different meals. It contains methods like CookPasta(), GrillChicken(), StirFryVegetables(), BakeCake(), MakeSandwich(), and PrepareSalad().
  2. Wife: This class acts as the facade and serves as the central coordinator for preparing different meals. It has methods like PrepareBreakfast, PrepareLunch, and PrepareDinner.
  3. Husband: This class represents the main program or the husband in the scenario. It creates an instance of the Wife class and requests the wife to prepare breakfast, lunch, and dinner using the respective methods.

Here's a detailed explanation of each part:

  1. The CookingSubsystem class contains various cooking methods (e.g., CookPasta, GrillChicken, etc.) that represent specific cooking tasks. These methods are the actual low-level tasks required to prepare each meal.
  2. The Wife class acts as the facade, providing high-level methods (PrepareBreakfast, PrepareLunch, PrepareDinner) to the husband (main program) for requesting meals. The wife uses these high-level methods to coordinate and perform the cooking tasks through the CookingSubsystem.
  3. In the PrepareBreakfast method, the wife uses the CookingSubsystem to make a sandwich by calling MakeSandwich() and prepares a salad by calling PrepareSalad(). The raw ingredients for the sandwich are provided as an array of strings (bread, cheese, etc.).
  4. In the PrepareLunch method, the wife takes two parameters: mainDish and sideDishes, representing the main dish and an array of side dishes for lunch. The wife simply displays the main dish and side dishes as part of preparing lunch. The actual cooking tasks for the main dish and side dishes are abstracted behind the facade.
  5. In the PrepareDinner method, the wife prepares dinner by cooking pasta, grilling chicken, stir-frying vegetables, and baking cake. The specific types of pasta, chicken, vegetables, and cake are provided as parameters to the method.
  6. The Husband class represents the main program, where the husband's role is implied. It creates an instance of the Wife class and requests breakfast, lunch, and dinner by calling the respective methods on the wife.
  7. When the husband (main program) runs, it interacts with the Wife class (facade) to request different meals. The husband doesn't need to know the details of individual cooking tasks or processes (encapsulated in the CookingSubsystem), as the wife abstracts those complexities behind the facade.

 

 

 

Overall, the facade pattern allows the husband (main program) to interact with the wife (facade) through simple high-level methods (PrepareBreakfast, PrepareLunch, PrepareDinner), hiding the complexity of the actual cooking tasks performed by the wife (coordinating with the CookingSubsystem). This simplifies the communication and provides a clear interface for the husband to request different meals without needing to understand the intricacies of the cooking processes.

 

So the facade design pattern simplifies complex subsystems by providing a unified, easy-to-use interface for clients. It promotes loose coupling, encapsulation, and abstraction, allowing clients to interact with the system without understanding its intricacies. Facades enhance code organization, maintainability, and flexibility by hiding implementation details, making the system more user-friendly and adaptable to changes.

 

Please note that if you want a technical example please see our E-commerce Shopping Cart Example of Facade Design Pattern.

 

Still you face problems, feel free to contact with me, I will try my best to help you.