Design patterns

As we said, SOLID principles are beyond any specific consideration on how to resolve a certain coding problem and even beyond languages or paradigms. However, before Robert Martin defined these principles, other patterns were already in use related to very distinct aspects of coding and structuring applications.

In real life, a class can use one or more patterns, making it diffuse the boundary between the two. Additionally, you can begin to use a simple pattern and evolve into other more complex patterns depending on the needs of our application.

In 1995, Eric Gamma, Richard Helm, Ralph Johnson, and John Vlissides (since then, the Gang of Four or GoF for short) published a book that has remained a reference point: Design Patterns: Elements of Reusable Object-Oriented Software.

The authors analyze a total of 23 design patterns applicable in different coding scenarios in order to solve different coding problems.

They divide the 23 patterns into three categories:

  • Creational: It includes these patterns:
    • Abstract Factory
    • Builder
    • Factory
    • Prototype
    • Singleton
  • Structural: It is composed of these patterns:
    • Adapter
    • Bridge
    • Composite
    • Decorator
    • Façade
    • Flyweight
    • Proxy
  • Behavioral: It is made up of the following patterns:
    • Chain of Responsibility
    • Command
    • Interpreter
    • Iterator
    • Mediator
    • Memento
    • Observer
    • State
    • Strategy
    • Template method
    • Visitor

Obviously, all these patterns are a lot to be covered in this chapter, even in a superficial way, but we're going to focus on the most frequently used ones and explain their advantages and programming in C#:

Design patterns

The .NET framework itself contains, among others, these patterns: Singleton, Strategy, Factory, Builder, Decorator, and several other patterns in different namespaces.

There are numerous statistic reports on the Internet about the GoF pattern's usage. Obviously, it's not a question of using this or that pattern because of general acceptance. On the contrary, the reasons to use them are based on the benefits these patterns offer in order to improve the quality of an application.

That said, I'll just review some of them to give you an idea about their possibilities of solving specific problems. However, an agreement seems to exist when placing the following eight patterns among the most used:

  • Construction: Singleton and Factory
  • Structural: Adapter, Decorator, and Façade
  • Behavioral: Command, Observer, and Strategy

Note that some patterns, such as Iterator, are not included here just because they're already present in the vast majority of the collection's libraries (such as in the System.Collections and System.Collections.Generic namespaces in .NET). Another typical case is Abstract Factory, which is widely used in ADO.NET.

Let's start with the most common (and reviled) of them all: Singleton.

Singleton

The Singleton pattern prevents the creation of more than one instance of a class. It's the most popular pattern because its implementation is required in a great variety of situations and many different languages (also in non-compiled languages, such as JavaScript).

At the same time, it's one of the most reviled because of general abuse of the pattern in many situations in which other patterns would be preferred or even no pattern is required at all (not to mention the difficulties that sometimes arise when including it in unit tests).

The way it should be coded requires the following:

  • The class should be responsible for creating the unique instance
  • The unique instance has to be accessible through a method in the class
  • The constructor should be private in order to avoid direct instantiation

To apply this pattern in our sample, we can imagine a new requisite: for instance, imagine that the user interface requires that either from the current main window or from other future windows, some user information showing the name of the user and the date/time at which the car is selected is available.

The shape of the new class should reflect the pattern and the values required:

public class UserInfoSingleton
{
  // A static variable for the instance, requires a lambda function,
  // since the constructor is private.
  private static readonly Lazy<UserInfoSingleton> instance =
  new Lazy<UserInfoSingleton>(() =>newUserInfoSingleton());

  // Private Constructor to avoid direct instantiation
  private UserInfoSingleton() {
    UserName = System.Environment.UserName;
    CarBuyingTime = DateTime.Now;
  }

  // Property to access the instance
  public static UserInfoSingleton Instance
  {
    get { return instance.Value; }
  }
  private string UserName { get; }
  private DateTime CarBuyingTime { get; }
}

Observe that this class is only for reading purposes, with no meaningful functionality. However, having it instantiated in this manner, no possible duplication is possible. There will always be a unique set of user information.

The class' instance is stored in the private static instance variable, and the constructor is private in order to avoid external instantiation. Actually, all members except the Instance property are private.

The other aspect of the class that you might wonder about is the Lazy<UserInfoSingleton> type of the instance member, which guarantees that the instance is thread-safe since it won't really be instantiated until it is used by a client of the class.

The Factory pattern

Wikipedia's definition of the Factory pattern states that, a Factory is actually a creator of objects which have a common interface, without exposing the instantiation logic.

Actually, this is what we did in the last modification in our sample, when we detached the instantiation into a CarFactory class.

With these changes, we divided the structure of the resulting objects into two parts:

  • The CarFactory class decides the state structure of the resulting object depending on the brand field (remember that the state of a class is defined by the set of values that its properties hold in a given instant of its execution).
  • SportsCar and SportsCarWithN are implementations of a behavior. Each one implements distinct behaviors with respect to the instant Speed value, and both share the same state structure (same field names and types).

In our sample, there is a dependency between the fields, since MaxSpeed and Photo directly depend on Brand, so they should be resolved at construction time. Generally speaking, when there aren't any dependencies of this type, the structure can be more flexible.

The Adapter pattern

The Adapter pattern is one of the most versatile, and it's intended to allow two components that were not originally designed to work together in order to integrate them in the cleanest way possible.

It is, therefore, especially suitable when we have to deal with legacy code, in which it is quite difficult, if not impossible, to modify fragments of the code, but we have the requirement to include new functionality.

The following schema shows the most common way to visually prototype the indirect path that the Adapter pattern implements in order to achieve this goal:

The Adapter pattern

As you can see in the schema, there is a client that uses a certain interface. When the original class needs to change or extend some behavior with minimal or no changes, Adapter is one of the most accepted solutions.

Imagine that we have a class that lists all car brands and that we cannot modify, with the following code:

class ShoppingCarsPortal
{
  static void Main(string[] args)
  {
    Console.Title = "Demo of the Adapter Pattern";
    ITarget adapter = new VendorAdapter();
    foreach (string brand in adapter.GetCars())
    {
      Console.WriteLine("Brand: " + brand);
    }
    Console.ReadLine();
  }
}

On the other hand, a new class has to be used in order to get the list of the cars still calling to the same adapter.GetCars() function. This class, named ListOfCarsProvider, holds a method called GetListOfCars:

public class ListOfCarsProvider
{
  public List<string> GetListOfCars()
  {
    List<string> carsList = newList<string>();
    carsList.Add("Ferrari");
    carsList.Add("Mercedes");
    carsList.Add("BMW");
    carsList.Add("Ford");
    return carsList;
  }
}

We can define a simple interface (ITarget), which defines the same method signature that the final class requires:

interface ITarget
{
  List<string> GetCars();
}

The next step is to make VendorAdapter implement ITarget. The trick is that we make the implementation of GetCars() call the new list of cars in ListOfCarsProvider:

class VendorAdapter : ITarget
{
  public List<string> GetCars()
  {
    ListOfCarsProvider adaptee = new ListOfCarsProvider();
    return adaptee.GetListOfCars();
  }
}

As you can see, we preserve the functionality of the base class but allow a new way to obtain the list of available cars. We provide a level of indirection with minimal changes.

Of course, the list is obtained at runtime, as expected:

The Adapter pattern

The Façade pattern

Another useful (and quite used) pattern in many circumstances is the Façade pattern. It's quite simple, and its main purpose is to unify processes dispersed in distinct functions of a library, giving access to them through a more simple, concrete set of methods.

Wikipedia collects some typical usages of this pattern, for example, when you want to do the following:

  • Make an external library easier to use
  • Give access to a library in a more readable way or with a more organized structure
  • Reduce the dependencies found in the management of an outside library

The graphic schema that represents this structure is usually represented in this manner:

The Façade pattern

This means that the façade its just another layer between a set of classes that can either be saved inside a larger library or disaggregated along distinct files. In any case, the pattern allows the unification of that functionality included in the assemblies.

No interface implementation is required since it's only a matter of calling the required methods, thus providing the business logic. You'll find the source code corresponding to the preceding schema in the demo called PatternFacade. The runtime doesn't have much interest in this since you can easily deduct how it works.

The Decorator pattern

The Decorator pattern is frequently used when you need to add a functionality to a procedure (often obtaining extra data to accompany the standard implementation) but you have to keep the current behavior as it is and only add the new functionality for certain scenarios.

If you think about it, this pattern enforces the application of the Open/Closed principle. The main code remains intact, but the pattern allows the functionality to grow in a controlled manner.

The situation is similar to the first implementation of our SportsClassWithN type of cars in our sample. The current functionality of the main class (SportsCar) is not to be changed. But some extra requirements would be needed in case the brand were a Mercedes (and later on, for the Ford brand as well). In this case, the new class inherited from the base class and added some behavior:

The Decorator pattern

Finally, the user interface decides which class is to be implemented at runtime, and in the case of the exception, it instructs the event handler to manage that exception.

The pattern admits (like most of them) slight variations in the way you implement it.

The Command pattern

The Command pattern is one of the most used patterns in the behavioral category. GoF authors define the pattern in this way: encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

As always, a level of indirection is provided. Instead of immediately executing a call, we are allowed to queue it, which has many advantages in a bunch of scenarios, especially now, when more and more implementations require asynchronous processing.

The key part of this pattern is that it decouples the object that invokes an operation from the one that has the knowledge to perform it.

A typical example that GoF authors state as canonical is about the menu's implementation in a classic user interface: in this case, you can implement several user interface artifacts to perform the same action (such as MenuItem and a toolbar's button) by having both of them perform the same action, that is, making both implement the same concrete Command subclass.

An example already implemented in .NET

Again, we can find the Command pattern implemented in a variety of places within .NET Framework. Perhaps one of the most evident patterns is something as simple as the procedure to close a window: you can do it in four different ways:

  • By clicking on the icon window to close it
  • Using the window menu (not the user menu) and selecting Close
  • By pressing Ctrl + F4
  • By calling this.close() in some of the window's code

All of the preceding ways provoke a command invocation, sending a WM_CLOSE message to the window.

Note

You can check the whole list of window messages that a window can handle at the dedicated site, Platform Invoke (http://www.pinvoke.net/).

Invoking this.close() in a window is a command invocation itself. The .NET Framework also sends one of these messages to be managed by the message's dispatcher window function.

You can intervene in this call thanks to the implementation of the Window.FormClosing event, which carries information about the command to be executed and allows it to cancel it by assigning the value of the e.Cancel property (EventArgs)to true.

Besides, you can find out the reason for this event to be launched, examining the e.CloseReason property that the e argument holds.

These two possibilities are available thanks to the implementation of the command pattern in the internal mechanism used to send WM_CLOSE messages to a window inside .NET Framework.

Note

We'll talk about the advanced aspects of .NET framework in the last chapter of this book, along with other techniques related to platform invocation.

The following capture resumes this window-closing scenario in the user interface of our initial demos:

An example already implemented in .NET

The Observer pattern

Again, we find another popular pattern that's widely implemented inside the .NET framework for distinct scenarios.

The MSDN documentation states that this pattern enables a subscriber to register with and receive notifications from a provider. It is suitable for any scenario that requires push-based notification.

A typical case of this pattern is implemented in order to link data in a model with the user interface, which shows it in distinct controls: DataGridViews, TextBoxes, and so on. When the user performs an action that implies a modification in the data shown in the UI—such as an update, a deletion, or a modification—the desired behavior is that these controls are automatically informed of the changes and they can update them in the UI.

This source suggests the steps to implement this pattern in .NET:

  • A provider needs to be in charge of sending notifications to the observer. It should be a class or a structure that implements the IObservable<T> interface, although its only requisite is implementing the IObservable<T>.Subscribe method. This is the one called by client observers that wish to receive notifications.
  • An observer that is the object that receives notifications from the provider. In this case, the class should implement the IObserver<T> interface, but it's required that it implement three methods that will be called by the provider:
    • IObserver<T>.OnNext, which provides new or current information
    • IObserver<T>.OnError, which is in charge of informing the observer about any error that has occurred
    • IObserver<T>.OnCompleted, which always marks the ending of notifications
  • If you think about the scenario, we have the typical communication scheme between a sender and a receiver. So, we also need a channel to transmit the information. In this case, we need a mechanism that allows providers to keep track of observers.
  • Such mechanism in .NET is usually assigned to an instance of System.Collections.Generics.List<T>, which is in charge of holding references to the implementations of IObserver<T>. This is a convenient way to handle references to an unlimited number of observers.
  • Usually, there is another object that stores data that the provider sends to its subscribed observers.

In a real-case scenario, it might depend on the solution you're building: Windows Presentation Foundation interfaces implement observable collections precisely with this purpose. Even other mechanisms that implement the MVC paradigm are capable of showing this behavior.

A well-known case outside the OOP world is the AngularJS Framework, which makes every data in the model observable and linkable to the user interface, implementing a double binding architecture that makes any change in the model automatically reflect in the user interface, using a special markup (the moustache syntax).

The Strategy pattern

The Strategy pattern is officially defined as a practice of defining a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Mainly, there are three participants:

  • The Strategy (or compositor) component responsible for defining a common interface for all algorithms to be managed
  • ConcreteStrategy, which implements the algorithm using the strategy interface
  • AContext, which has three roles: it gets configured with the ConcreteStrategy object, maintains a reference to the Strategy object, and—optionally—it can define an interface to allow Strategy to access its data.

In code, a typical example might be when you have to use different sorting strategies (in any collection), but depending on other circumstances, you might like to choose which sorting algorithm you'd like to use, for instance, QuickSort, Shell, or Bubble.

You can define an object (SortingClass) with a method responsible for sorting, but depending on a value, the instance is created from another instance of the actual sorting method.

The following code gives you an idea about how to use this pattern. The key is that SortingClass is called with distinct instances of the desired algorithm:

SortingStrategy shell = newSortingClass(newShell());
SortingStrategy quick = newSortingClass(newQuickSort());
SortingStrategy bubble = newSortingClass(newBubble());

With this approach, the user interface will always call the same method for sorting, whatever its name, but the actual sorting mechanism will be decided at runtime.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.50.222