Chain of responsibility

A useful pattern you need to be familiar with is the Chain of Responsibility pattern so we will use it as an example. With this pattern, we will set up a collection or chain of classes for handling a request. The idea is the request will pass through each class until it is handled. This illustration uses a car service center, where each car will pass through the different sections of the center until the service is complete.

Let's start by defining a collection of flags that will be used to indicate the services required:

[Flags]
enum ServiceRequirements
{
None = 0,
WheelAlignment = 1,
Dirty = 2,
EngineTune = 4,
TestDrive = 8
}
The FlagsAttribute in C# is a great way of using a bit field to hold a collection of flags. The single field will be used to indicate the enum values that are turned on by using bitwise operations. 

The Car will contain a field to capture what servicing is required and a field that returns true when the service has been completed:

class Car
{
public ServiceRequirements Requirements { get; set; }

public bool IsServiceComplete
{
get
{
return Requirements == ServiceRequirements.None;
}
}
}

One thing to point out is that a Car is considered to have its service completed once all the requirements have been completed, as represented by the IsServiceComplete property.

An abstract base class will be used to represent each of our service technicians in the following manner:

abstract class ServiceHandler
{
protected ServiceHandler _nextServiceHandler;
protected ServiceRequirements _servicesProvided;

public ServiceHandler(ServiceRequirements servicesProvided)
{
_servicesProvided = servicesProvided;
}
}

Take note that the service provided by the class that extends the ServiceHandler class, in other words the technician, is required to be passed in.

The service will then be performed by using the bitwise NOT operation (~) to turn off the bit on the given Car, indicating the service is required in the Service method: 

public void Service(Car car)
{
if (_servicesProvided == (car.Requirements & _servicesProvided))
{
Console.WriteLine($"{this.GetType().Name} providing {this._servicesProvided} services.");
car.Requirements &= ~_servicesProvided;
}

if (car.IsServiceComplete || _nextServiceHandler == null)
return;
else
_nextServiceHandler.Service(car);
}

If all services have been completed on the car and/or there are no more services, the chain is stopped. If there is another service and a car is not ready, then the next service handler is called.

This approach requires the chain to be set and the preceding example shows this being done using the SetNextServiceHandler() method to set the next service to be performed:

public void SetNextServiceHandler(ServiceHandler handler)
{
_nextServiceHandler = handler;
}

The service specialists include a Detailer, Mechanic, WheelSpecialist, and a QualityControl engineer. The ServiceHandler representing a Detailer is shown in the following code:

class Detailer : ServiceHandler
{
public Detailer() : base(ServiceRequirements.Dirty) { }
}

The mechanic, whose specialty is tuning the engine, is shown in the following code:

class Mechanic : ServiceHandler
{
public Mechanic() : base(ServiceRequirements.EngineTune) { }
}

The wheel specialist is shown in the following code:

class WheelSpecialist : ServiceHandler
{
public WheelSpecialist() : base(ServiceRequirements.WheelAlignment) { }
}

And last is quality control, who will take the car for a test drive:

class QualityControl : ServiceHandler
{
public QualityControl() : base(ServiceRequirements.TestDrive) { }
}

The service center technicians have been defined, so the next step is to service a couple of cars. This will be illustrated in the Main code block, starting with constructing the required objects:

static void Main(string[] args)
{
var mechanic = new Mechanic();
var detailer = new Detailer();
var wheels = new WheelSpecialist();
var qa = new QualityControl();

The next step will be to set up the handling order for the different services:

    qa.SetNextServiceHandler(detailer);
wheels.SetNextServiceHandler(qa);
mechanic.SetNextServiceHandler(wheels);

Then two calls will be made to the mechanic, which is the start of the chain of responsibility:

    Console.WriteLine("Car 1 is dirty");
mechanic.Service(new Car { Requirements = ServiceRequirements.Dirty });

Console.WriteLine();

Console.WriteLine("Car 2 requires full service");
mechanic.Service(new Car { Requirements = ServiceRequirements.Dirty |
ServiceRequirements.EngineTune |
ServiceRequirements.TestDrive |
ServiceRequirements.WheelAlignment });

Console.Read();
}

An important thing to note is the order in which the chain is set. For this service center, the mechanic first performs tuning, followed by the wheels being aligned. Then, a test drive is performed and after that, the car is worked up in detail. Originally, the test drive used to be performed as the last step, but the service center determined that, on rainy days, this required the car details to be repeated. A bit of a silly example, but it illustrates the benefit of having the chain of responsibility defined in a flexible manner.

The preceding screenshot shows the display after our two cars have been serviced.