Design Pattern Examples
Overview of object-oriented design patterns
HandlerChain Pattern

Diagram of the Handler Chain pattern

The Handler Chain or Chain of Responsibility is a very old pattern. A "chain" of handlers are built up. An object is passed to the head of the chain for handling. That first handler decides whether it can handle the object or not. if so, it handles it and returns. Otherwise, the handler passes the object to the next handler in the chain. This continues until no more handlers remain or a handler processes the object. The advantage of a chain like this is handlers can be inserted into or removed from the chain at runtime.

Windows uses this approach for handling messages passed to windows, where each window handler either handles the message and/or passes the message on to the next window handler in the chain until the default handler is eventually called. By inserting a handler into the chain, it is possible to intercept the message and thus making it possible to add new functionality to an existing window.

A variation on this is where an additional parameter determines whether a handler that handled the object should pass the object to the next handler instead of returning.

Another variation is a list of handlers to be called at some point. For example, the atexit() function in the C library takes a function pointer that is added to a list that is then called in reverse order. Technically, the handlers aren't actually chained together except through the containing list but the effect is the same; handlers in a dynamic list are called until done.

The key to a Handler Chain is that the chain of handlers is dynamic and the handlers are invoked in order until all handlers have been invoked. A common variation is to allow a handler to stop the processing so no additional handlers are called.

Handlers are set up through any number of ways, depending on what the handlers do. For example, with Windows message handlers, the chain is updated when a new window is created or destroyed.

The Handler Chain, wherein an object is passed to a number of handlers until processed, is also a form of the Observer pattern, where an object is passed to a number of handlers. Unlike the Observer pattern, though, a handler in a Handler Chain can abort the sequence of calls to additional handlers.

In an "ideal" object-oriented implementation, a Handler Chain is composed of handler objects that are linked to the previous handler object and the next handler object in the chain. The head of the chain has an empty previous link while the last handler object in the chain has an empty next link. Each handler object has a Process() method that either processes the incoming arguments or calls the Process() method on the next handler object in the chain, if any.

In addition, each handler object knows how to insert itself and remove itself from the chain. This implies each handler object has an Add() and Remove() method, where Add() adds to the end of the chain (or insert based on some qualifier) and Remove() removes from the chain. The Add() method requires the head of the chain. The Remove() method doesn't need the head of the chain as the links to the previous and next handlers are available in the handler itself.

The advantage of this approach is the program only needs to deal with the head handler object in the chain, either calling Process() on the head object or calling Add() (or Remove() on the handler object) with a handler object.

A simpler approach is to designate a different class to handle the chain. An instance of this class has the necessary Process(), Add(), and Remove() methods on it but internally the handler objects are stored in a traditional (and thoroughly-tested) container. The handler of the chain can also take steps to protect the list from multi-threaded incursions. The handler is just a single object that is passed around and it always exists even if there are no handlers.

How to Use

Links to the Handler Chain classes
C++ C# Python C
HandlerChain class HandlerChain class HandlerChain class HandlerChain_SendMessage()
HandlerChain_AddWindow()
HandlerChain_RemoveWindow()
MessageWindow class MessageWindow class MessageWindow class MessageWindow structure
MessageWindow_Create()
MessageWindow_Destroy()
IMessageHandler interface IMessageHandler interface IMessageHandler interface MessageWindow_ProcessMessage()
WindowRectangle class WindowRectangle class WindowRectangle class WindowRectangle structure
WindowRectangle_PointInside()

The example presented here is a collection of "windows" represented by the MessageWindow class. Each window has a common message handler as implemented through the IMessageHandler interface. The windows are stored in the HandlerChain collection and can interact with that collection.

ButtonDown messages are pushed in by the user of the HandlerChain class, selecting and deselecting windows based on a position associated with the ButtonDown message.

A ButtonUp message is pushed in by the user of the HandlerChain class. In a window that is selected, the message causes an action to be taken, although in this example, only one action is supported and that is the Close action. However, the Close action is taken only if the message position is in the "Close" region in the upper right corner of the window.

A "Close" action causes the window to send a Close message to the collection. This Close message is processed only by the currently selected window and causes the window to remove itself from the collection so it no longer receives messages.

(RUST: The Rust version does not support the Close message like the Button Down and Button Up messages. This is due to the strict nature of ownership and borrowing (through references) that Rust enforces. The output from the Rust version therefore differs slightly when it comes to the closing of "Window 2".)

C++

void HandlerChain_Exercise()
{
std::cout << std::endl;
std::cout << "HandlerChain Exercise" << std::endl;
// Construct a handler chain and populate with windows that can
// handle messages.
HandlerChain::unique_ptr_t handlerChain = std::make_unique<HandlerChain>();
std::cout << " Handler Chain at start:" << std::endl;
std::cout << handlerChain->ToString() << std::endl;
// Now pass messages to the windows.
std::cout << " Select Window 2" << std::endl;
handlerChain->SendMessage(std::make_unique<Message>(MessageType::ButtonDown, MessagePosition(22, 1)).get());
handlerChain->SendMessage(std::make_unique<Message>(MessageType::ButtonUp, MessagePosition(22, 1)).get());
std::cout << " Current handler chain:" << std::endl;
std::cout << handlerChain->ToString() << std::endl;
std::cout << " Select Window 3" << std::endl;
handlerChain->SendMessage(std::make_unique<Message>(MessageType::ButtonDown, MessagePosition(35, 11)).get());
handlerChain->SendMessage(std::make_unique<Message>(MessageType::ButtonUp, MessagePosition(35, 11)).get());
std::cout << " Current handler chain:" << std::endl;
std::cout << handlerChain->ToString() << std::endl;
std::cout << " Select Window 1" << std::endl;
handlerChain->SendMessage(std::make_unique<Message>(MessageType::ButtonDown, MessagePosition(4, 4)).get());
handlerChain->SendMessage(std::make_unique<Message>(MessageType::ButtonUp, MessagePosition(4, 4)).get());
std::cout << " Current handler chain:" << std::endl;
std::cout << handlerChain->ToString() << std::endl;
std::cout << " Close Window 2" << std::endl;
handlerChain->SendMessage(std::make_unique<Message>(MessageType::ButtonDown, MessagePosition(24, 0)).get());
handlerChain->SendMessage(std::make_unique<Message>(MessageType::ButtonUp, MessagePosition(24, 0)).get());
std::cout << " Current handler chain:" << std::endl;
std::cout << handlerChain->ToString() << std::endl;
std::cout << " Done." << std::endl;
}
static void _HandlerChain_ConstructWindowChain(int windowIds[3])
Helper function to construct a list of windows. Messages will be passed to these windows via the Hand...
@ ButtonUp
Take an action on the currently selected window.
@ ButtonDown
Selects a window based on position.
Position of the message in global coordinates (same scope of coordinates as windows)....

C#

public void Run()
{
Console.WriteLine();
Console.WriteLine("Handler Chain Exercise");
// Construct a handler chain and populate with windows that can
// handle messages.
HandlerChain handlerChain = new HandlerChain();
Console.WriteLine(" Handler Chain at start:");
Console.WriteLine(handlerChain);
// Now pass messages to the windows.
Console.WriteLine(" Select Window 2");
handlerChain.SendMessage(new Message(MessageType.ButtonDown, new MessagePosition(22, 1)));
handlerChain.SendMessage(new Message(MessageType.ButtonUp, new MessagePosition(22, 1)));
Console.WriteLine(" Current handler chain:");
Console.WriteLine(handlerChain);
Console.WriteLine(" Select Window 3");
handlerChain.SendMessage(new Message(MessageType.ButtonDown, new MessagePosition(35, 11)));
handlerChain.SendMessage(new Message(MessageType.ButtonUp, new MessagePosition(35, 11)));
Console.WriteLine(" Current handler chain:");
Console.WriteLine(handlerChain);
Console.WriteLine(" Select Window 1");
handlerChain.SendMessage(new Message(MessageType.ButtonDown, new MessagePosition(4, 4)));
handlerChain.SendMessage(new Message(MessageType.ButtonUp, new MessagePosition(4, 4)));
Console.WriteLine(" Current handler chain:");
Console.WriteLine(handlerChain);
Console.WriteLine(" Close Window 2");
handlerChain.SendMessage(new Message(MessageType.ButtonDown, new MessagePosition(24, 0)));
handlerChain.SendMessage(new Message(MessageType.ButtonUp, new MessagePosition(24, 0)));
Console.WriteLine(" Current handler chain:");
Console.WriteLine(handlerChain);
Console.WriteLine(" Done.");
}
MessageType
Type of message handled by MessageWindow.
Represents a message sent to the windows. A message contains a type and a position.

Python

def HandlerChain_Exercise():
print()
print("Handler Chain Exercise")
# Construct a handler chain and populate with windows that can
# handle messages.
handlerChain = HandlerChain()
print(" Handler Chain at start:")
print(handlerChain.ToString())
# Now pass messages to the windows.
print(" Select Window 2")
handlerChain.SendMessage(Message(MessageType.ButtonDown, MessagePosition(22, 1)))
handlerChain.SendMessage(Message(MessageType.ButtonUp, MessagePosition(22, 1)))
print(" Current handler chain:")
print(handlerChain.ToString())
print(" Select Window 3")
handlerChain.SendMessage(Message(MessageType.ButtonDown, MessagePosition(35, 11)))
handlerChain.SendMessage(Message(MessageType.ButtonUp, MessagePosition(35, 11)))
print(" Current handler chain:")
print(handlerChain.ToString())
print(" Select Window 1")
handlerChain.SendMessage(Message(MessageType.ButtonDown, MessagePosition(4, 4)))
handlerChain.SendMessage(Message(MessageType.ButtonUp, MessagePosition(4, 4)))
print(" Current handler chain:")
print(handlerChain.ToString())
print(" Close Window 2")
handlerChain.SendMessage(Message(MessageType.ButtonDown, MessagePosition(24, 0)))
handlerChain.SendMessage(Message(MessageType.ButtonUp, MessagePosition(24, 0)))
print(" Current handler chain:")
print(handlerChain.ToString())
print(" Done.")

C

void HandlerChain_Exercise(void)
{
printf("\nHandlerChain Exercise\n");
// Construct several windows that can handle messages. These are
// automatically handled to the handler chain list during construction.
int windowIds[3] = { 0 };
_ShowHandlerChain("Handler Chain at start:");
// Now pass messages to the windows.
printf(" Select Window 2\n");
Message buttonDownMessage;
Message_Initialize(&buttonDownMessage, ButtonDown, 22, 1);
HandlerChain_SendMessage(-1, &buttonDownMessage);
Message buttonUpMessage;
Message_Initialize(&buttonUpMessage, ButtonUp, 22, 1);
HandlerChain_SendMessage(-1, &buttonUpMessage);
_ShowHandlerChain("Current handler chain:");
printf(" Select Window 3\n");
Message_Initialize(&buttonDownMessage, ButtonDown, 35, 11);
HandlerChain_SendMessage(-1, &buttonDownMessage);
Message_Initialize(&buttonUpMessage, ButtonUp, 35, 11);
HandlerChain_SendMessage(-1, &buttonUpMessage);
_ShowHandlerChain("Current handler chain:");
printf(" Select Window 1\n");
Message_Initialize(&buttonDownMessage, ButtonDown, 4, 4);
HandlerChain_SendMessage(-1, &buttonDownMessage);
Message_Initialize(&buttonUpMessage, ButtonUp, 4, 4);
HandlerChain_SendMessage(-1, &buttonUpMessage);
_ShowHandlerChain("Current handler chain:");
printf(" Close Window 2\n");
Message_Initialize(&buttonDownMessage, ButtonDown, 24, 0);
HandlerChain_SendMessage(-1, &buttonDownMessage);
Message_Initialize(&buttonUpMessage, ButtonUp, 24, 0);
HandlerChain_SendMessage(-1, &buttonUpMessage);
_ShowHandlerChain("Current handler chain:");
printf(" Removing all windows as part of clean-up.\n");
printf(" Done.\n");
}
static void _ShowHandlerChain(const char *prompt)
Helper function to display the current handler chain.
static void _HandleChain_DestroyWindows(int windowIds[3])
Helper function to destroy all windows that have been created.
void HandlerChain_SendMessage(int windowId, Message *message)
Send a message to each of the handlers in the list, protected by a multi-threading lock.
void Message_Initialize(Message *message, MessageType type, int x, int y)
Initialize a Message structure.

RUST

(Apologies. Doxygen does not understand Rust syntax and therefore cannot colorize the code.)

pub fn handlerchain_exercise() -> Result<(), String> {
println!("");
println!("HandlerChain Exercise");
let mut handler_chain = HandlerChain::new();
_handlerchain_construct_window_chain(&mut handler_chain);
println!(" Handler Chain at start:");
println!("{}", handler_chain.to_string());
// Now pass messages to the windows.
println!(" Select Window 2");
handler_chain.send_message(&Message::new(MessageType::ButtonDown, 22, 1));
handler_chain.send_message(&Message::new(MessageType::ButtonUp, 22, 1));
println!(" Current handler chain:");
println!("{}", handler_chain.to_string());
println!(" Select Window 3");
handler_chain.send_message(&Message::new(MessageType::ButtonDown, 35, 11));
handler_chain.send_message(&Message::new(MessageType::ButtonUp, 35, 11));
println!(" Current handler chain:");
println!("{}", handler_chain.to_string());
println!(" Select Window 1");
handler_chain.send_message(&Message::new(MessageType::ButtonDown, 4, 4));
handler_chain.send_message(&Message::new(MessageType::ButtonUp, 4, 4));
println!(" Current handler chain:");
println!("{}", handler_chain.to_string());
println!(" Close Window 2");
handler_chain.send_message(&Message::new(MessageType::ButtonDown, 24, 0));
handler_chain.send_message(&Message::new(MessageType::ButtonUp, 24, 0));
println!(" Current handler chain:");
println!("{}", handler_chain.to_string());
println!(" Done.");
Ok(())
}

See Also