Monday, February 16, 2009

Tom’s Patterns Cheat Sheet for .NET – Part 1: Template Method, Strategy, Observer, Adapter, Proxy Patterns

This post started as a brownbag presentation I put together last year on Russ Olsen's Design Patterns in Ruby, so he deserves attribution. Parts also are based on Jeffrey Richter's classic Applied Microsoft® .NET Framework Programming.

Template method

The template method implements an algorithm that makes use of the virtual or abstract methods, which subclasses can specialize.


public abstract class AbstractClass
{
public void TemplateMethod()
{
// A real template method example would implement a more complex algorithm
Operation1();
Operation2();
Operation3();
Operation4();
}
// These operations may be abstract or virtual
protected abstract void Operation1();
protected abstract void Operation2();
protected abstract void Operation3();
protected abstract void Operation4();
}

This is useful when the outline of an algorithm is fixed but the specific implementations of pieces of the algorithm may change. E.g. a class that encrypts and compresses data might delegate the specific encryption and compression algorithms to use to subclasses.


Strategy Pattern

Traditional strategy pattern diagram:

You might think of this as "algorithm injection." The "strategy" object is just a wrapper for a method. Clients "inject" the method they want to use by implementing their own strategy object and injecting it into the context. Similar to the template method pattern, but the client in this case doesn't have to subclass the class containing the template method.

In these days of anonymous methods, lambda methods, and code blocks the traditional strategy pattern diagram looks like a circumlocution. Nowadays we would rather visualize passing method contents around directly, without the need for an object wrapper, even if the compiler is really providing the object behind the scenes. I'm not really sure how to draw it in UML, but it would look something like this:

where the code blocks are the strategy operation method contents. A simple example of the strategy pattern:


List<string> animals = new List<string> { "lion", "tiger", "giraffe", "elephant", "fox", "dog", "bear" };
animals.Sort(new Comparison<string>((x, y) => x.Length.CompareTo(y.Length)));

List<string> is the context. Comparison<string> is just a delegate; that's the strategy. (x, y) => x.Length.CompareTo(y.Length) is a lambda method; that's the strategy operation method contents.


Observer Pattern:

The object being observed keeps a list of objects that are observing it, and calls a notification method in each observer whenever its state changes. Objects register themselves to observe a subject by calling its AddObserver method, and unregister themselves by calling the RemoveObserver method. Simple implementation of the observer pattern:


abstract class Observer
{
public abstract void NotifyChanged(Subject subject);
}

class Subject
{
public List<Observer> Observers = new List<Observer>();

bool _foo = false;


private void NotifyObservers()
{
foreach (Observer observer in Observers)
observer.NotifyChanged(this);
}

public bool Foo
{
set {
_foo = value;
NotifyObservers();
}
}
}

For the sake of brevity I'm publicly exposing the List<Observer> observers field. Its Add and Remove methods will act as the AddObserver and RemoveObserver methods. When the state of the subject changes, it iterates the observer list, calling their NotifyChanged methods.

The above code isn't very practical in C# due to its lack of support for multiple inheritance. Any observer would burn its one and only base class just so it could listen to the subject's notifications. Instead, we would want to create a delegate for the NotifyChanged method, which the observers could use to have the subject call back to them when the subject changes.

I have a good friend whose favorite interview question for .NET engineers is, "How do you implement the observer pattern in .NET?" It stumps most candidates because .NET provides such deep native support for the pattern that we tend not to think about it:


class Subject
{
event EventHandler Changed;

bool _foo = false;

private void OnChanged(EventArgs e)
{
Changed(this, e);
}

public bool Foo
{
set {
_foo = value;
OnChanged(EventArgs.Empty);
}
}
}

The "event" keyword hydrates into a lot of observer goodness. First, it causes the compiler to auto-generate the delegate for the Changed method that I said we would want above. Remember that a delegate is just a class. This takes the place of the abstract Observer class in the first code listing. Second, it causes a delegate field to be added to the Subject class. This takes the place of the Observers field in the first code listing. And finally, it causes Add and Remove methods to be added to the Subject class.

.NET delegates come with built-in support for "delegate chaining," or managing lists of delegates. So the auto-generated delegate field can already handle lists observers, and the Changed(this, e) call automatically iterates the list.


Adapter Pattern

The goal of the pattern is to wrap the "adaptee" in a class that matches the interface expected by the client. It's useful when you have an existing class that provides the functionality needed by the client, but using a different interface than the one it expects. Here's a simple code sample of the adapter pattern:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Adapter
{
class Client
{
private Target _target;

public Client(Target target) {
_target = target;
}

public void Foo() {
_target.OperationA();
}
}

class Target
{
public virtual void OperationA() { }
}

class Adaptee
{
public void OperationB() {

Console.WriteLine("Performed OperationB");
}
}

class Adapter : Target
{
private Adaptee _adaptee;


public Adapter(Adaptee adaptee) {
_adaptee = adaptee;
}

public override void OperationA() {
_adaptee.OperationB();
}
}

class Program
{
static void Main(string[] args)
{
Client client = new Client(new Adapter(new Adaptee()));

client.Foo();
Console.ReadLine();
}
}
}


Proxy Pattern:

The proxy pattern is used for inserting a class between clients and the real service that they are connecting to. Common types of proxies include protection proxies, which perform an access check before allowing the client to call the service, and remote proxies, which encapsulate the complexities of making method calls on a service in another process or on another machine.

Proxies are everywhere. If we create a console application in Visual Studio, and add a service reference to a default WCF service, Visual Studio auto-generates one for us:


Service1Client is a client proxy that implements the IService1 interface. "GetData" is the operation implemented by the service. In this case the proxy doesn't match the traditional diagram exactly, because the proxy doesn't hold anything we could call a reference to the real service. But the point of that reference in the traditional diagram is to convey that the proxy has the ability to pass calls through to the real service, and our WCF proxy does exactly that.

No comments:

Post a Comment

Followers