Design Patterns In C#

Design patterns are reusable solutions to common problems that arise during software development. They provide a set of best practices and guidelines for creating software that is maintainable, scalable, and efficient. There are many design patterns that can be used in C#, and they are generally classified into three categories:

  1. Creational Patterns
  2. Structural Patterns
  3. Behavioral Patterns

Creational Patterns:

Creational patterns are used to create objects in a way that is flexible and efficient. These patterns focus on abstracting the process of object creation and hiding the implementation details from the client code. The most common creational patterns in C# are:

  1. Singleton pattern: This pattern ensures that only one instance of a class is created and provides global access to it.
  2. Factory pattern: This pattern provides an interface for creating objects, but lets subclasses decide which classes to instantiate.
  3. Abstract Factory pattern: This pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.
  4. Builder pattern: This pattern separates the construction of a complex object from its representation, allowing the same construction process to create different representations.
  5. Prototype pattern: This pattern allows new objects to be created by cloning existing objects, instead of creating new ones from scratch.

Structural Patterns

Structural patterns focus on the composition of classes and objects to form larger structures. They help to simplify the design of complex systems by identifying relationships between objects and defining interfaces between them. The most common structural patterns in C# are:

  1. Adapter pattern: This pattern allows incompatible classes to work together by converting the interface of one class to that of another.
  2. Bridge pattern: This pattern separates an abstraction from its implementation, allowing them to vary independently.
  3. Composite pattern: This pattern allows a group of objects to be treated as a single object, with a common interface.
  4. Decorator pattern: This pattern adds new functionality to an object by wrapping it in another object that adds the required behavior.
  5. Facade pattern: This pattern provides a simplified interface to a complex system, hiding its complexity from the client code.

Behavioral Patterns:

Behavioral patterns focus on the communication between objects and the distribution of responsibilities among them. They help to define the behavior of an object or a group of objects and improve the flexibility of the system. The most common behavioral patterns in C# are:

  1. Observer pattern: This pattern defines a one-to-many dependency between objects, so that when one object changes state, all its dependents are notified and updated automatically.
  2. Command pattern: This pattern encapsulates a request as an object, allowing it to be queued, logged, and undone.
  3. Template Method pattern: This pattern defines the skeleton of an algorithm in a superclass, allowing subclasses to override specific steps of the algorithm.
  4. State pattern: This pattern allows an object to change its behavior when its internal state changes.
  5. Strategy pattern: This pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable.

Design Patterns in With C# Real-time Example

Let's take the Observer pattern as an example. The Observer pattern is a behavioral pattern that allows one-to-many communication between objects. In this pattern, an object (called the subject) maintains a list of its dependents (called observers) and notifies them automatically of any state changes, so that they can update their state accordingly.

To illustrate the Observer pattern in C#, let's consider the following scenario: You have a weather station that measures temperature, humidity, and pressure, and you want to display this information on a dashboard. You can use the Observer pattern to update the dashboard automatically whenever the weather station measurements change.

Following is the C# code for this example:

using System; using System.Collections.Generic; // Define the subject (weather station) interface interface IWeatherStation { void AddObserver(IWeatherObserver observer); void RemoveObserver(IWeatherObserver observer); void NotifyObservers(); } // Define the observer (dashboard) interface interface IWeatherObserver { void Update(float temperature, float humidity, float pressure); } // Implement the subject (weather station) class class WeatherStation : IWeatherStation { private List<IWeatherObserver> observers = new List<IWeatherObserver>(); private float temperature; private float humidity; private float pressure; public void AddObserver(IWeatherObserver observer) { observers.Add(observer); } public void RemoveObserver(IWeatherObserver observer) { observers.Remove(observer); } public void NotifyObservers() { foreach (IWeatherObserver observer in observers) { observer.Update(temperature, humidity, pressure); } } public void SetMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; NotifyObservers(); } } // Implement the observer (dashboard) class class Dashboard : IWeatherObserver { private float temperature; private float humidity; private float pressure; public void Update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; Display(); } public void Display() { Console.WriteLine("Temperature: {0} F, Humidity: {1} %, Pressure: {2} inHg", temperature, humidity, pressure); } } // Test the Observer pattern class Program { static void Main(string[] args) { WeatherStation weatherStation = new WeatherStation(); Dashboard dashboard = new Dashboard(); weatherStation.AddObserver(dashboard); weatherStation.SetMeasurements(72.5f, 50f, 30.0f); weatherStation.SetMeasurements(70.0f, 55f, 29.9f); weatherStation.SetMeasurements(68.5f, 60f, 29.8f); weatherStation.RemoveObserver(dashboard); Console.ReadKey(); } }
//Output: Temperature: 72.5 F, Humidity: 50 %, Pressure: 30 inHg Temperature: 70 F, Humidity: 55 %, Pressure: 29.9 inHg Temperature: 68.5 F, Humidity: 60 %, Pressure: 29.8 inHg

Above C# example program demonstrates the Observer design pattern, which is used when there is a one-to-many relationship between objects such that when one object changes state, all its dependents are notified and updated automatically.

In the above program, the WeatherStation class is the subject that notifies its observers about changes in temperature, humidity, and pressure. It implements the IWeatherStation interface, which defines methods for adding, removing, and notifying observers.

The Dashboard class is an observer that displays the temperature, humidity, and pressure on a dashboard. It implements the IWeatherObserver interface, which defines the update method that gets called by the subject to update its state.

What is design pattern in C#

In the Main method, an instance of the WeatherStation class and an instance of the Dashboard class are created. The dashboard object is added as an observer to the weatherStation object using the AddObserver method. Then, the weather station's SetMeasurements method is called three times with different values to simulate changes in the weather conditions. Each time the SetMeasurements method is called, it updates the weather station's internal state and calls the NotifyObservers method, which in turn calls the Update method on each observer.

After the third call to SetMeasurements, the dashboard object is removed as an observer using the RemoveObserver method. Finally, the program waits for a key to be pressed before terminating.