Tim Van Wassenhove

Passionate geek, interested in Technology. Proud father of two

30 May 2006

Building a chain of responsibility with delegates

Imagine that you have to write a function that verifies if there is a license available for a given clientID. Suppose that there are a couple of possibilities to find an available license. Your code would probably look like the following

// This code verifies if the client with the given clientID is licensed
// returns the licenseID or 0 if no license is available
public Int32 IsLicensed(Int32 clientID) 
{
	int result = 0;

	// verify if there is already a license 'assigned' to the client
	result = IsAssigned(clientID);

	if (result == 0) 
	{
		// find a dedicated license (license that is bound to the given client)
		result = IsDedicated(clientID);

		if (result == 0) 
		{
			// find a nondedicated license (license that can be used by any client)
			result = IsNonDedicated(clientID);
		}
	}

	return result;
}

It’s obvious that this structures becomes more complex as the number of possible ways to get a license grows. If you look a while at the structure you’ll notice a pattern: each function (IsAssigned, IsDedicated, IsNonDedicted) verifies if there is a license availble. If the function didn’t find a license the next function is performed. If you translate this to OO you would end up with something similar to the following

// this methods tries to find an available license for the given clientID
// returns the licenseID or 0 if no license was found
delegate Int32 FindLicenseMethod(Int32 clientID);

public class LicenseFinder 
{
	private FindLicenseMethod method;
	private LicenseFinder next;

	public LicenseFinder(FindLicenseMethod, method, LicenseFinder next) 
	{
		this.method = method;
		this.next = next;
	}

	// property for the next licensefinder in the chain
	public Next 
	{
		get { return next; }
		set { next = val; }
	}

	public Int32 GetLicense(Int32 clientID) 
	{
		Int32 result = method(clientID);

		if (result == 0 && Next != null) 
		{
			result = Next.GetLicense(clientID);
		}

		return result;
	}

	public Int32 IsLicensed(Int32 clientID) 
	{
		LicenseFinder f = new LicenseFinder(
		new FindLicenseMethod(IsAssigned), new LicenseFinder(
		new FindLicenseMethod(IsDedicated), new LicenseFinder(
		new FindLicenseMethod(IsNonDedicated), null))));

		return f.GetLicense(clientID);
	}
}