Facade Design Pattern in C# with Example

1. Definition

The Facade Design Pattern provides a unified interface to a set of interfaces in a subsystem. It defines a higher-level interface that makes the subsystem easier to use, thereby hiding its complexities.

2. Problem Statement

Imagine working with a complex library or framework that requires performing multiple steps to achieve certain operations. Directly interacting with the intricate parts of this system can be cumbersome and prone to errors. Moreover, if changes happen within the complex system, your code will need revisions too.

3. Solution

By introducing a Facade, you provide a simplified and stable interface to clients, hiding the intricacies of the underlying complex system. If changes occur in the system, only the Facade might need adjustments, thus isolating potential changes from the clients.

4. Real-World Use Cases

1. Home automation systems where a single command like "Good Night" turns off lights, locks doors, and sets the alarm.

2. Computer booting process where a press of a button initiates a series of intricate startup operations.

3. Simplifying access to a complex financial system with a unified interface.

5. Implementation Steps

1. Identify a simpler, unified interface that can represent the functionalities of the complex subsystem.

2. Implement the Facade class by composing the complex subsystems and routing the Facade method calls to the appropriate subsystem objects.

3. Client code should use the Facade instead of calling the subsystem methods directly.

6. Implementation in C#

// Complex Subsystem Classes
public class Authenticator
{
    public bool Authenticate(string username, string password)
    {
        // Logic to authenticate user
        return username == "user" && password == "pass";
    }
}

public class Logger
{
    public void Log(string message)
    {
        Console.WriteLine($"Log entry: {message}");
    }
}

public class DataProcessor
{
    public void ProcessData()
    {
        Console.WriteLine("Processing data...");
    }
}

// Facade
public class ApplicationFacade
{
    private Authenticator _authenticator;
    private Logger _logger;
    private DataProcessor _processor;

    public ApplicationFacade()
    {
        _authenticator = new Authenticator();
        _logger = new Logger();
        _processor = new DataProcessor();
    }

    public void RunApplication(string username, string password)
    {
        if (_authenticator.Authenticate(username, password))
        {
            _logger.Log("Authentication successful");
            _processor.ProcessData();
        }
        else
        {
            _logger.Log("Authentication failed");
        }
    }
}

public class Program
{
    public static void Main()
    {
        ApplicationFacade facade = new ApplicationFacade();
        facade.RunApplication("user", "pass");
    }
}

Output:

Log entry: Authentication successful
Processing data...

Explanation:

In the provided example, Authenticator, Logger, and DataProcessor represent the complex subsystem with multiple operations. 

The ApplicationFacade class simplifies the interaction with this subsystem. It routes the RunApplication call to the appropriate subsystem classes and methods. 

Client code, represented by the Program class, then only interacts with the Facade, making the entire process streamlined and more intuitive.

7. When to use?

1. Use the Facade Pattern when you want to provide a simple interface to a complex subsystem, which might get more complicated over time.

2. When you want to decouple client code from subsystem components, promote subsystem independence and portability.

3. To layer your subsystems. Each Facade can become an entry point to a specific level of a subsystem.


Comments