Imagine that you went to cafe with your friends. Cafe is somewhat weird, there is not enough room, and you have to pass food to other person if it is not for you. Your best friend took place the most closed to end of the table, so he is first who gets order. Cause he slept not enough in the night he dies for at least one cap of something with coffee and a lot of meat, since he did not eat during the day. Next to your friend is you and then your girlfriend near the wall. You want soup and she wants cappuccino. She have none to pass food to.

Chain Of Responsibility

I hope that whole mechanics of the design pattern Chain Of Responsibility is understandable. We have some set or chin of handlers (visitors of cafe), that can handle command (food in our example). If handler cannot process command it passes it to its successor if it exists.

Handler

In our example general interface for handler could be following abstract base class:

    public abstract class WierdCafeVisitor
{
public WierdCafeVisitor CafeVisitor { get; private set; }

protected WierdCafeVisitor(WierdCafeVisitor cafeVisitor)
{
CafeVisitor = cafeVisitor;
}

public virtual void HandleFood(Food food)
{
// If I cannot handle other food, passing it to my successor
if (CafeVisitor != null)
{
CafeVisitor.HandleFood(food);
}
}
}

As we can see by default food is passed to next cafe visitor in chain, if it exists.

Lets now take a look on realization that is more suitable for your persnickety friend:

    public class BestFriend : WierdCafeVisitor
{
public List<Food> CoffeeContainingFood { get; private set; }
public BestFriend(WierdCafeVisitor cafeVisitor) : base(cafeVisitor)
{
CoffeeContainingFood = new List<Food>();
}

public override void HandleFood(Food food)
{
if(food.Ingradients.Contains("Meat"))
{
Console.WriteLine("BestFriend: I just ate {0}. It was testy.", food.Name);
return;
}
if (food.Ingradients.Contains("Coffee") && CoffeeContainingFood.Count < 1)
{
CoffeeContainingFood.Add(food);
Console.WriteLine("BestFriend: I have to take something with coffee. {0} looks fine.", food.Name);
return;
}
base.HandleFood(food);
}
}

Implementations of two other handlers – Me and GirlFriend probably are understandable, but anyway will show realization of GirlFriend visitor:

    public class GirlFriend : WierdCafeVisitor
{
public GirlFriend(WierdCafeVisitor cafeVisitor) : base(cafeVisitor)
{
}

public override void HandleFood(Food food)
{
if(food.Name == "Cappuccino")
{
Console.WriteLine("GirlFriend: My lovely cappuccino!!!");
return;
}
base.HandleFood(food);
}
}

That’s simple: girl wants cappuccino, but since she is last in chain she will not get it before friend will not have his cap of something with coffee.

Usage

Now lets take a look on usage. We create two cappuccinos, two soups and one meat. Then we pass those one by one into BestFriend hands: 

            var cappuccino1 = new Food("Cappuccino", new List<string> {"Coffee", "Milk", "Sugar"});
var cappuccino2 = new Food("Cappuccino", new List<string> {"Coffee", "Milk"});

var soup1 = new Food("Soup with meat", new List<string> {"Meat", "Water", "Potato"});
var soup2 = new Food("Soup with potato", new List<string> {"Water", "Potato"});
var meat = new Food("Meat", new List<string> {"Meat"});

var girlFriend = new GirlFriend(null);
var me = new Me(girlFriend);
var bestFriend = new BestFriend(me);

bestFriend.HandleFood(cappuccino1);
bestFriend.HandleFood(cappuccino2);
bestFriend.HandleFood(soup1);
bestFriend.HandleFood(soup2);
bestFriend.HandleFood(meat);

Output:

BestFriend: I have to take something with coffee. Cappuccino looks fine.
GirlFriend: My lovely cappuccino!!!
BestFriend: I just ate Soup with meat. It was testy.
Me: I like Soup. It went well.
BestFriend: I just ate Meat. It was testy.

As we can see from output girl got only second cappuccino and you have been forced to eat soup without meat :)

What is also interesting is that we can add another one handler after girlfriend, say bag for dog, and everything that none likes will go there.

My design patterns table

If you haven't subsribed yet, you can subsribe below: