Patterns: behavior · 3 MIN READ

Chain of Responsibility: ordered handlers

Stop or delegate deliberately and make short-circuit order visible.

Stop or delegate deliberately and make short-circuit order visible. A chain passes a request through handlers that can decide whether to continue. Trace the worked Go example, then compare the benefit with the cost before applying this design to your own project.

Behavioral pattern · A MAP OF THE IDEA

  1. First handler checks the request
  2. Failure short-circuits the chain
  3. Next handler receives accepted input

Useful when

  • Handlers can independently accept or reject
  • Middleware concerns should be composable

Watch out

  • Short-circuit order changes behavior
  • Silent swallowing makes failures hard to trace

Implementation & operation cost: Low to medium

Fit depends on the task

Small tool or CLI4/5
Domain-rich application5/5
Independent distributed services5/5

Editorial suitability, not benchmarks or a universal ranking. Styles describe different axes and can be combined.

01

The design decision

A chain passes a request through handlers that can decide whether to continue. Validation commonly stops at the first failure. Unlike an unconditional pipeline, a responsibility chain defines which handler accepts, rejects or delegates the request.

02

A complete Go example

Read this program from the entry point and follow the calls shown in the diagram. The output is included at the end so you can check the behavior without a compiler.

go
package main

import (
	"errors"
	"fmt"
	"strings"
)

type Check func(string) error

func Validate(input string, checks ...Check) error {
	for _, check := range checks {
		if err := check(input); err != nil {
			return err
		}
	}
	return nil
}
func NonEmpty(s string) error {
	if strings.TrimSpace(s) == "" {
		return errors.New("empty")
	}
	return nil
}
func Short(s string) error {
	if len(s) > 5 {
		return errors.New("too long")
	}
	return nil
}

func main() {
	fmt.Println(Validate("", NonEmpty, Short))
	fmt.Println(Validate("gopher", NonEmpty, Short))
}

// Output:
// empty
// too long
Read the code

Validate delegates in order and returns immediately on an error. The second check is never asked about an empty string after the first failure. An HTTP middleware chain can use a similar continuation shape with a next handler.

03

Tradeoffs and the simpler alternative

Ordering is part of behavior: authentication should usually precede work that leaks private data. Keep chains observable and avoid handlers that silently swallow failures. If every step must always run, an explicit sequence or result-collecting validator may be clearer.

TAKE THIS WITH YOU

May handle, reject or delegate in a defined order. Ordering is part of behavior: authentication should usually precede work that leaks private data. Keep chains observable and avoid handlers that silently swallow failures. If every step must always run, an explicit sequence or result-collecting validator may be clearer.

Check your understanding

Which statement best describes Chain of Responsibility: ordered handlers?

Go to the source

Progress stays in this browser. No account needed.