Practical Design Patterns in C# – Bridge

Intent

The bridge pattern is designed to separate the implementation of a functionality from its interface. The benefits of this approach are seen when the functionality has multiple implementations which can be swapped out without changing the API. But the separation of concerns can also prove useful when the system is backed by only a single implementation. The client API can continue to remain stable even if the entire implementation changes, because the client is shielded from its effects.

The source code for this design pattern, and all the others, can be viewed in the Practical Design Patterns repository.

Solution

This example demonstrates the use of this pattern by building a playlist which stores and cycles through audio tracks. Tracks can be retrieved in linear or random order. The playlist can either stop after it has cycled over all the items, or loop back and begin afresh.

public class Playlist
{
    private readonly IPlaylistImpl _playlistImpl;

    public async Task PlayAsync()
    {
        …
        var item = _playlistImpl.Next();
        while (item != null)
        {
            // Perform an operation on the item.
            …

            // Pick the next item.
            item = _playlistImpl.Next();
        }
    }
}

This class defines the public API of the playlist. The client populates the audio tracks through the usual collection API (not shown here), after which it invokes the PlayAsync method to start iterating through the list. Once it reaches the end of the list, it stops.

PlantUML Syntax:<br />
!theme vibrant</p>
<p>class Playlist {<br />
+PlayAsync()<br />
}</p>
<p>interface IPlaylistImpl {<br />
+IsEmpty()<br />
+Next()<br />
+Reset()<br />
}</p>
<p>Playlist o-down-> IPlaylistImpl</p>
<p>class Client #palegreen</p>
<p>Client -left-> Playlist</p>
<p>LinearPlaylistImpl .up.|> IPlaylistImpl<br />
RandomizedPlaylistImpl .up.|> IPlaylistImpl<br />

This is coupled with the implementation, defined by the IPlaylistImpl interface, and referenced by the _playlistImpl field.

public interface IPlaylistImpl
{
    bool IsEmpty();

    string Next();

    void Reset();
}

This interface is implemented by the LinearPlaylistImpl and RandomizedPlaylistImpl classes, each of which approaches the collection of items differently. The linear playlist iterates over each audio track in the same order that they are stored in the items array.

public class LinearPlaylistImpl : IPlaylistImpl
{
    private readonly string[] _items;

    private readonly IEnumerator _enumerator;

    public LinearPlaylistImpl(IEnumerable<string> items)
    {
        _items = items.ToArray();
        _enumerator = _items.GetEnumerator();
    }

    public bool IsEmpty()
    {
        return _items.Count() == 0;
    }

    public string Next()
    {
        if (_enumerator.MoveNext())
        {
            return _enumerator.Current as string;
        }

        return null;
    }

    public void Reset()
    {
        _enumerator.Reset();
    }
}

The randomized playlist picks an item at random from the list, marks it visited so it is not repeated, and stops after all audio tracks have been visited.

public class RandomizedPlaylistImpl : IPlaylistImpl
{
    private readonly List<string> _items;

    private readonly Random _random = new Random((int)DateTime.Now.Ticks);

    private readonly Queue<string> _usedItems;

    public RandomizedPlaylistImpl(IEnumerable<string> items)
    {
        _items = new List<string>(items);
        _usedItems = new Queue<string>();
    }

    public bool IsEmpty()
    {
        var c1 = _items.Count;
        var c2 = _usedItems.Count;

        return c1 + c2 == 0;
    }

    public string Next()
    {
        if (_items.Count > 0)
        {
            var index = _random.Next(_items.Count);
            var item = _items[index];
            _items.Remove(item);
            _usedItems.Enqueue(item);

            return item;
        }

        return null;
    }

    public void Reset()
    {
        while (_usedItems.Count > 0)
        {
            var item = _usedItems.Dequeue();
            _items.Add(item);
        }
    }
}

Emergent Behaviour

The real magic of this approach becomes more evident once you add looping to the Playlist class. Since the effect of looping is the same on all implementations, it is best stored in the Playlist itself.

public class Playlist
{
    …
    public bool IsLooping()
    {
        get;
        set;
    }
    …
}

When all items have been iterated through, the state of this property is checked. If looping is not enabled, the playback loop exits. If it is set, the playlist implementation is reset back to the first index and the iteration process is begun afresh.

Practical Design Patterns in C# – Adapter

Intent

The intent of this pattern is to convert the API to an existing library, usually to encapsulate legacy code, simplify its use or provide an alternative output format, into a different interface that a client expects.

The source code for this design pattern, and all the others, can be viewed in the Practical Design Patterns repository.

Solution

There are many examples of this interface in the real world. Cross-platform GUI toolkits are adapters around the underlying API for each supported platform. Clients can continue to use the API provided by GTK+, Windows Forms or Qt, for their applications that run on Windows, macOS or GNOME. The library takes care of translating the API invocations into native equivalents.

There are many simpler examples of the adapter pattern. A data-driven website is an adapter. It lets web browsers retrieve contents from a database over HTTP instead of running SQL queries on the database engine. It converts the API from SQL to HTTP.

PlantUML Syntax:</p>
<p>!theme vibrant</p>
<p>class DiskInfoProvider {<br />
+CollectAsync()<br />
}</p>
<p>class Completed <<event>></p>
<p>DiskInfoProvider –> ManagementClass : create<br />
DiskInfoProvider –> ManagementOperationObserver : create<br />
DiskInfoProvider ..> Completed : handle</p>
<p>class Client #palegreen</p>
<p>Client -right-> DiskInfoProvider : uses</p>
<p>ManagementOperationObserver -right-> Completed : dispatch</p>
<p>ManagementClass –> ManagementOperationObserver : notify<br />

Modern-day C# applications are often built around the task-based asynchronous pattern, but may need to utilise legacy frameworks or libraries that do not have task-based APIs. The Windows Management Instrumentation (WMI) API is a good example. The ManagementClass and ManagementOperationObserver types work collectively to query the WMI database and raise an event when the results are retrieved.

public class WmiClient
{
  public void GetDiskData()
  {
    var management = new ManagementClass("Win32_LogicalDisk");
    var watcher = new ManagementOperationObserver();
    watcher.Completed += WatcherCompletedHandler;
    management.GetInstances(watcher);
  }

  private void WatcherCompletedHandler(object sender, CompletedEventArgs e)
  {
    // Consume the results of the operation.
    …
  }
}

The code below illustrates how an adapter can convert this into a task-based asynchronous interface.

public class DiskInfoProvider
{
  public async Task<PropertyDataCollection> CollectAsync()
  {
    var tcs = new TaskCompletionSource<PropertyDataCollection>();
    var watcher = new ManagementOperationObserver();

    // The event handler that gets invoked by the watcher.
    var completedHandler = default(CompletedEventHandler);
    completedHandler = new CompletedEventHandler((sender, e) =>
    {
      var tcsLocal = tcs;
      try
      {
        if (e.Status == ManagementStatus.NoError)
        {
          // The operation was completed without any errors.
          tcsLocal.SetResult(e.StatusObject.Properties);
          return;
        }

        if (e.Status == ManagementStatus.CallCanceled || e.Status == ManagementStatus.OperationCanceled)
        {
          // The task was cancelled before it could be completed.
          tcsLocal.SetCanceled();
          return;
        }

        // An exception occurred during the operation.
        tcsLocal.SetException(new Exception($"Runtime error {e.Status}"));
        return;
      }
      finally
      {
        // Clean up the event handlers.
        watcher.Completed -= completedHandler;
      }
    });

    // Wire up the event handler and begin the operation.
    watcher.Completed += completedHandler;
    var management = new ManagementClass("Win32_LogicalDisk");
    management.GetInstances(watcher);
    return tcs.Task;
  }
}

DiskInfoProvider encapsulates ManagementOperationObserver and ManagementClass. The client instantiates DiskInfoProvider and awaits the results from CollectAsync().

public class WmiClient
{
  public void GetDiskData()
  {
    var provider = new DiskInfoProvider();
    var diskProperties = await provider.CollectAsync();
  }
}

Many structural patterns serve similar roles, but have a singular differentiator between themselves. Adapters and proxies are at parallel purpose to each other. A proxy provides a matching replacement to all or most of its underlying API. An adapter changes the API to meet the client’s requirement.

Practical Design Patterns in C# – Singleton

Intent

The Singleton pattern is one of the simplest and most commonly used in practice. Its purpose is to restrict a class to only one instance throughout the lifetime of the application. This is desirable in cases when there is one or only a few resources available and access has to be controlled.

Problem

A common use case is resource pools to objects which are expensive to acquire. Some examples are a database connection pool or a local cache of the results of a network operation. The object pool itself is a design pattern worthy of its own detailed discussion. In this article, however, I will limit myself to describing its implementation as a singleton.

The source code for this design pattern, and all the others, can be viewed in the Practical Design Patterns repository.

Solution

This pattern has multiple possible implementations in C#. The ones shown below are built purely on the language features. There are still other ways of limiting a class to single instance through the use of dependency injection frameworks. Those techniques are not covered here.

PlantUML Syntax:<br />
!theme vibrant</p>
<p>class ConnectionPool {<br />
-{static}instance:ConnectionPool<br />
-released:ISet<br />
-acquired:ISet<br />
+Acquire()<br />
+Release(connection:IDbConnection)<br />
+{static}Instance:ConnectionPool<br />
}<br />

Single-threaded, Lazy Initialisation

The first example is the simplest possible implementation of this pattern. This version is not thread-safe, but can use lazy initialisation in a single-threaded scenario. If there are multiple threads attempting to invoke the Instance property of this class, many or all of them will cause an invocation of the constructor. In this case, it has to be eagerly initialised.

public sealed class ConnectionPool
{
    private static ConnectionPool _instance;

    private ISet<IDbConnection> _released;

    private ISet<IDbConnection> _acquired;

    private ConnectionPool()
    {
        // Initialise the collection objects
    }

    public IDbConnection Acquire()
    {
        // Retrieve a free connection instance
        // Instantiate a new one if there are no free instances
        // Move the connection instance into the acquired collection
    }

    public void Release(IDbConnection connection)
    {
        // Remove the connection from the acquired collection
        // Add it into the released collection
    }

    public static ConnectionPool Instance
    {
        get
        {
            if (null == _instance)
            {
                _instance = new ConnectionPool();
            }

            return _instance;
        }
    }
}

This could be an acceptable solution for simple situations where multiple threads are not involved. But with multi-threaded applications being more or less the norm in a language like C#, the actual number of situations where this code will be safe to use are very limited. This is truer than ever before with the advent of opaque multi-threading as supported by TPL. In my experience, it is safer to err on the side of caution and not use this implementation in production.

In multi-threaded situations, the risk of invoking the constructor multiple times can be mitigated by calling the Instance property immediately on startup before launching any additional threads, i.e. by using eager initialisation. But the cost of eager initialisation and high risk of introducing synchronisation bugs in the future makes it an unattractive option.

If you need thread-safety in your singleton, you need a different solution. The simplest way is to use a lock.

Multi-threaded, Lazy Initialisation

public sealed class ConnectionPool
{
    private static ConnectionPool _instance;

    …

    private readonly object padlock = new { };

    private ConnectionPool()
    {
        // Initialise the collection objects
    }

    public IDbConnection Acquire()
    {
        …
    }

    public void Release(IDbConnection connection)
    {
        …
    }

    public static ConnectionPool Instance
    {
        get
        {
            lock (padlock)
            {
                if (null == _instance)
                {
                    _instance = new ConnectionPool();
                }

                return _instance;
            }
        }
    }
}

The drawback to this technique is that every invocation of Instance has to acquire a lock. This is an unnecessary performance hit after an instance has been created once, because the property does not modify the instance ever afterwards.

Again, this is not incorrect. The code will perform exactly according to the pattern specification, and can be used if bleeding-edge performance is not an absolute must-have or the instance is not being referenced frequently. In practice, locking impacts performance by a single-digit percentage.

Lock-free, Multi-threaded, Lazy Initialisation

But faster it can get. The advantages of ease in maintaining and reasoning about lock-free code are a bonus.

public class ConnectionPool
{
    private static readonly ConnectionPool _instance = new ConnectionPool();

    static ConnectionPool()
    {
    }

    private ConnectionPool()
    {
    }

    public IDbConnection Acquire()
    {
        …
    }

    public void Release(IDbConnection connection)
    {
        …
    }

    public static ConnectionPool Instance
    {
        get
        {
            return _instance;
        }
    }
}

The above example contains a static constructor along with the regular instance constructor. The static constructor itself does not require any code. But as a side-effect of its presence in the code, the type initialiser method of this class is only executed when a static or instance field is accessed for the first time, or when a static, instance or virtual method of the type is invoked for the first time.

This is a by-product of the language design and described in detail by Jon Skeet on his website. The runtime runs this check before creating a new type, and guarantees that this executes only once. This implementation leverages this behaviour to constrain the class instantiation to just once, only when the Instance property of the class is invoked for the first time.

Practical Design Patterns in C# – Prototype

Intent

The prototype pattern simplifies creating instances of a class by copying the contents of an existing instance to create a new one. This alleviates the cost of any expensive computation or I/O being performed in the constructor, or simply copies over the state of an existing object to the new instance for further modification.

The source code for this design pattern, and all the others, can be viewed in the Practical Design Patterns repository.

Problem

This article demonstrates a document editor that has the ability to make and display multiple concurrent snap shots of a document. Each can be reviewed and edited individually and compared with each other. The process begins with a single document in memory, which the user can edit before cloning. When a draft is ready, the user duplicates the object by invoking a command from the UI. This copies the contents of the document over into a new instance. The document also contains a date and time field which is modified to match the time when the duplicate is created.

PlantUML Syntax:<br />
!theme vibrant</p>
<p>interface ICloneable<T> {<br />
+ Clone()<br />
}</p>
<p>class Document {<br />
-version<br />
+CreatedOn<br />
+Text<br />
+Clone()<br />
}</p>
<p>class Client #palegreen</p>
<p>Document .up.|> ICloneable</p>
<p>Document -down-> Document : clones</p>
<p>Client -right-> Document</p>
<p>

Both versions now exist in memory simultaneously and the user can cycle between them as needed.

Solution

For this, there must be a way for the document class to be duplicated. The .NET framework already defines an interface called System.ICloneable with a method called Clone() for just this purpose. The caveat of this technique is that the return type of the Clone() method is an object, thus requiring type-casting of the object instance which is returned. It is quite easy to declare a generic version of the ICloneable interface to avoid this problem.

public interface ICloneable<T>
{
    T Clone();
}

The Document class implements this interface as shown below. This snippet also shows the CreatedOn and Text properties that the Document class exposes.

[Serializable]
public class Document : ICloneable<Document>
{
    private int _version = 0;

    public Document()
    {
        CreatedOn = DateTime.UtcNow;
        Text = string.Empty;
        _version = 1;
    }

    public DateTime CreatedOn
    {
        get;
        private set;
    }

    public string Text
    {
        get;
        set;
    }

    public Document Clone()
    {
        Document clone;

        using (var stream = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(stream, this);
            var self = stream.ToArray();

            stream.Seek(0, SeekOrigin.Begin);
            clone = (Document)formatter.Deserialize(stream);
            clone.CreatedOn = DateTime.UtcNow;
            clone._version++;
        }

        return clone;
    }
}

When the document instance has to be duplicated, the client calls the Clone method to create a whole new instance of the object based on the contents of the original.

The implementation of the Clone method itself is highly specific to the language and platform in use. The example above demonstrates a straightforward binary copy by serializing the class into a byte array, then immediately serializing it back into a new object instance. This mandates that the Document class be decorated with the Serializable attribute.

This technique works in C# and other .NET languages which implement the BinaryFormatter and MemoryStream APIs.

Another technique to create a duplicate is calling the constructor and setting each property and field individually. Since the Clone method is a part of the same class, it has access to the private members of the new instance as well.

private Document Clone()
{
    var clone = new Document();
    clone.CreatedOn = DateTime.UtcNow;
    clone.Text = Text;
    clone._version++;

    return clone;
}

Finally, the .NET Framework provides a built-in method called MemberwiseClone, which creates a shallow object copy.

private Document Clone()
{
    var clone = (Document)base.MemberwiseClone();
    clone.CreatedOn = DateTime.UtcNow;
    clone._version++;

    return clone;
}

All methods shown above create a shallow copy of the object. In order to create a deep copy, each reference type that the Document class uses must implement a similar Clone method which is invoked when the instance has to be cloned. This can quickly escalate out of hand if these classes further reference other types. For this reason, this pattern is best applied to classes that use value types only.

Practical Design Patterns in C# – Builder

Intent

The builder pattern abstracts multiple steps required to create a complex object into a coherent interface. Objects that need several input parameters are prime candidates for refactoring behind a builder object.

The source code for this design pattern, and all the others, can be viewed in the Practical Design Patterns repository.

Problem

To understand the benefits of this pattern, we must first analyse some code that does not utilise it.

var message = new MailMessage("john@example.com",
                "jane@example.com",
                "101 Ways to Refactor",
                "Lorem ipsu…");

Quick, can you identify what is each parameter in this statement? Is John the sender or recipient? How do you add more than one recipient? How does one create HTML-formatted email? These questions are not immediately obvious. And adding more configurability into the MailMessage class would make for ever longer constructor calls.

A more readable alternative is clearly required, at least to retain the maintenance programmer’s sanity for the future. And there’s our hook for the builder pattern.

PlantUML Syntax:<br />
!theme vibrant</p>
<p>interface IMessageBuilder<TMessage> {<br />
+AddressedTo(recipient:string):EmailBuilder<br />
+From(sender:string):EmailBuilder<br />
+WithBody(body:string):EmailBuilder<br />
+WithSubject(subject:string):EmailBuilder<br />
+GetResults():TMessage<br />
}</p>
<p>class EmailBuilder<MailMessage><br />
EmailBuilder ..|> IMessageBuilder<br />
EmailBuilder -left-> MailMessage : builds</p>
<p>class JsonBuilder<string><br />
JsonBuilder ..|> IMessageBuilder<br />
JsonBuilder -right-> string : builds</p>
<p>class Client #palegreen</p>
<p>Client –> EmailBuilder : calls<br />
Client –> JsonBuilder : calls<br />

Solution

The fundamental type in this example is the builder itself, EmailBuilder in this case. This class separates the components of the message into discrete methods.

public class EmailBuilder
{
    private MailMessage _message;

    public EmailBuilder()
    {
        _message = new MailMessage();
    }

    public EmailBuilder AddressedTo(string recipient)
    {
        …
    }

    public EmailBuilder From(string sender)
    {
        …
    }

    public EmailBuilder WithBody(string body)
    {
        …
    }

    public EmailBuilder WithSubject(string subject)
    {
        …
    }

    public MailMessage GetResults()
    {
        return _message;
    }
}

The client code consumes this interface by invoking each method one after the other. All methods in the builder class return the instance itself (i.e. this) so that multiple methods can be chained together into a single, fluid statement.

var builder = new EmailBuilder();
var message = builder.From("john@example.com")
    .AddressedTo("jane@example.com")
    .AddressedTo("jim@example.com")
    .WithSubject("101 Ways to Refactor")
    .WithBody("Lorem ipsu…")
    .GetResults();

This simple class already makes the code exponentially readable and maintainable. But there’s more!

What if the program has to create multiple types of messages, such as an email plus a browser notification encoded into a JSON object? The API from the EmailBuilder can be easily extracted into an IMessageBuilder interface, then applied to different types of builders.

public interface IMessageBuilder<T>
{
    IMessageBuilder WithSubject(string subject);

    IMessageBuilder<T> WithBody(string body);

    IMessageBuilder<T> From(string sender);

    IMessageBuilder<T> AddressedTo(string recipient);

    T GetResults();
 }

This is a generic interface as the return type of each builder differs, depending on the type of message it creates. As a result, the EmailBuilder class definition and method signatures change as shown below. Any code that consumes this class is not affected.

public class EmailBuilder : IMessageBuilder<MailMessage>
{
    private MailMessage _message;

    public EmailBuilder()
    {
        _message = new MailMessage();
    }

    public IMessageBuilder<MailMessage> AddressedTo(string recipient)
    {
        …
    }

    public IMessageBuilder<MailMessage> From(string sender)
    {
        …
    }

    public IMessageBuilder<MailMessage> WithBody(string body)
    {
        …
    }

    public IMessageBuilder<MailMessage> WithSubject(string subject)
    {
        …
    }

    public MailMessage GetResults()
    {
        return _message;
    }
}

This done, we can move on to the JSON builder. For this example, we use types defined in the wildly popular Json.NET library from Newtonsoft.

public class JsonBuilder : IMessageBuilder<string>
{
    private StringBuilder _builder;

    private JsonTextWriter _writer;

    public JsonBuilder()
    {
        _builder = new StringBuilder();
        var sw = new StringWriter(_builder);
        _writer = new JsonTextWriter(sw);
        _writer.WriteStartObject();
    }

    public IMessageBuilder<string> AddressedTo(string recipient)
    {
        _writer.WritePropertyName("AddressedTo");
        _writer.WriteValue(recipient);
        return this;
    }

    public IMessageBuilder<string> From(string sender)
    {
        _writer.WritePropertyName("From");
        _writer.WriteValue(sender);
        return this;
    }

    public IMessageBuilder<string> WithBody(string body)
    {
        _writer.WritePropertyName("Body");
        _writer.WriteValue(body);
        return this;
    }

    public IMessageBuilder<string> WithSubject(string subject)
    {
        _writer.WritePropertyName("Subject");
        _writer.WriteValue(subject);
        return this;
    }

    public string Build()
    {
        _writer.WriteEndObject();
        return _builder.ToString();
    }
}

The client code must instantiate the JsonBuilder and invoke the same methods on it as it does on any other builder. Each builder can have its own customisations, such as only storing a single recipient’s name in the JSON object, which gets overwritten by any subsequent call to AddressedTo().

var builder = new JsonBuilder();
var message = builder.From("john@example.com")
    .AddressedTo("jane@example.com")
    .AddressedTo("jim@example.com")
    .WithSubject("101 Ways to Refactor")
    .WithBody("Lorem ipsu…")
    .GetResults();