Skip to content

Behavioural Patterns

Behavioral patterns take care of effective communication and the assignment of responsibilities between objects.

PatternPurpose
StrategyDefine a family of algorithms, put each in a separate class, and make their objects interchangeable
ObserverDefine a subscription mechanism to notify multiple objects about events happening to observed objects
CommandTurn requests into stand-alone objects containing all request information
IteratorTraverse elements of a collection without exposing the underlying representation
StateLet an object alter its behavior when its internal state changes
Chain of ResponsibilityPass requests along a chain of handlers where each decides to process or forward
Template MethodDefine the skeleton of an algorithm in a superclass, letting subclasses override specific steps
VisitorSeparate algorithms from the objects on which they operate
MediatorReduce chaotic dependencies by forcing objects to collaborate through a mediator
MementoStore and restore the previous state of an object without revealing implementation details

Error generating PlantUML diagram: connect ECONNREFUSED 127.0.0.1:8080

@startuml
hide empty members
skinparam backgroundColor #ffffff
skinparam Shadowing false
skinparam DefaultFontName Arial
skinparam DefaultFontSize 13
skinparam ArrowColor #475569
skinparam rectangleBorderColor #64748b
skinparam rectangleBackgroundColor #f8fafc
skinparam classBackgroundColor #f8fafc
skinparam classBorderColor #64748b
skinparam interfaceBackgroundColor #ecfdf5
skinparam interfaceBorderColor #10b981
skinparam noteBackgroundColor #fef3c7
skinparam noteBorderColor #d97706
class Client {
+ main()
}
class Context {
- strategy: Strategy
+ setStrategy(Strategy)
+ executeStrategy()
}
interface Strategy {
+ execute()
}
class ConcreteStrategyA {
+ execute()
}
class ConcreteStrategyB {
+ execute()
}
class ConcreteStrategyC {
+ execute()
}
Client --> Context
Client ..> ConcreteStrategyA
Client ..> ConcreteStrategyB
Client ..> ConcreteStrategyC
Context o--> Strategy
Strategy <|-- ConcreteStrategyA
Strategy <|-- ConcreteStrategyB
Strategy <|-- ConcreteStrategyC
note right of Context::executeStrategy
strategy.execute()
end note
note right of Client::main
// Create strategies
strategyA = new ConcreteStrategyA()
strategyB = new ConcreteStrategyB()
// Create context
context = new Context()
// Set and execute strategy A
context.setStrategy(strategyA)
context.executeStrategy()
// Switch to strategy B
context.setStrategy(strategyB)
context.executeStrategy()
end note
@enduml
  • Context: Maintains a reference to a Strategy object and delegates it to execute the algorithm
  • Strategy: Common interface for all concrete strategies
  • ConcreteStrategy: Implements the algorithm using the Strategy interface
  • Navigation Apps - Calculate routes using different strategies (fastest, shortest, avoid highways, public transport)
  • Payment Processing - Different payment methods (credit card, PayPal, cryptocurrency)
  • Compression Algorithms - Various compression strategies (ZIP, RAR, 7z)
  • Sorting Algorithms - Different sorting implementations based on data characteristics

Error generating PlantUML diagram: connect ECONNREFUSED 127.0.0.1:8080

@startuml
hide empty members
skinparam backgroundColor #ffffff
skinparam Shadowing false
skinparam DefaultFontName Arial
skinparam DefaultFontSize 13
skinparam ArrowColor #475569
skinparam rectangleBorderColor #64748b
skinparam rectangleBackgroundColor #f8fafc
skinparam classBackgroundColor #f8fafc
skinparam classBorderColor #64748b
skinparam interfaceBackgroundColor #ecfdf5
skinparam interfaceBorderColor #10b981
skinparam noteBackgroundColor #fef3c7
skinparam noteBorderColor #d97706
class Client {
+ main()
}
class Subject {
- observers: List<Observer>
- state: State
+ attach(Observer)
+ detach(Observer)
+ setState(State)
+ notify()
}
interface Observer {
+ update()
}
class ConcreteObserverA {
+ update()
}
class ConcreteObserverB {
+ update()
}
Client --> Subject
Client --> ConcreteObserverA
Client --> ConcreteObserverB
Subject o--> Observer
Observer <|-- ConcreteObserverA
Observer <|-- ConcreteObserverB
note right of Subject::notify
for each observer in observers:
observer.update()
end note
note right of Subject::setState
this.state = state
notify() // Notify all observers
end note
note right of Client::main
// Create subject and observers
subject = new Subject()
observerA = new ConcreteObserverA()
observerB = new ConcreteObserverB()
// Register observers
subject.attach(observerA)
subject.attach(observerB)
// Change state - triggers notification
subject.setState(newState)
// Unregister an observer
subject.detach(observerB)
end note
@enduml
  • Subject: Maintains a list of observers and notifies them of state changes
  • Observer: Interface that defines the update method for objects that should be notified
  • ConcreteObserver: Implements the Observer interface to respond to updates
  • UI Event Listeners - Button clicks, form submissions, keyboard events
  • Subscription Systems - YouTube channels, newsletters, RSS feeds
  • Stock Market Feeds - Real-time price updates to multiple traders
  • Social Media - Notification systems for likes, comments, and shares

Error generating PlantUML diagram: connect ECONNREFUSED 127.0.0.1:8080

@startuml
hide empty members
skinparam backgroundColor #ffffff
skinparam Shadowing false
skinparam DefaultFontName Arial
skinparam DefaultFontSize 13
skinparam ArrowColor #475569
skinparam rectangleBorderColor #64748b
skinparam rectangleBackgroundColor #f8fafc
skinparam classBackgroundColor #f8fafc
skinparam classBorderColor #64748b
skinparam interfaceBackgroundColor #ecfdf5
skinparam interfaceBorderColor #10b981
skinparam noteBackgroundColor #fef3c7
skinparam noteBorderColor #d97706
class Client {
+ main()
}
class Invoker {
- command: Command
+ setCommand(Command)
+ executeCommand()
}
interface Command {
+ execute()
}
class ConcreteCommand {
- receiver: Receiver
+ execute()
}
class Receiver {
+ action()
}
Client --> Receiver: creates >
Client --> ConcreteCommand: creates >
Client --> Invoker: configures >
Invoker o--> Command
Command <|-- ConcreteCommand
ConcreteCommand --> Receiver
note right of ConcreteCommand::execute
receiver.action()
end note
note right of Invoker::command
// can optionally contain
// to maintain history / undo / redo
commandStack: Stack
end note
note right of Client::main
// Create receiver
receiver = new Receiver()
// Create command with receiver
command = new ConcreteCommand(receiver)
// Setup invoker with command
invoker = new Invoker()
invoker.setCommand(command)
// Execute the command
invoker.executeCommand()
end note
note "Commands encapsulate actions\nand their parameters" as N1
@enduml
  • Command - Interface with an execute method
  • ConcreteCommand - Implements Command and links to a Receiver
  • Invoker - Asks the command to carry out the action
  • Receiver - Knows how to perform the operations
  • Remote Controls - TV remotes, smart home devices
  • Text Editors - Undo/redo functionality
  • Game Commands - Action queues, replay systems
  • Task Schedulers - Job queues, batch processing
  • Transactional Systems - Database transactions with rollback

Error generating PlantUML diagram: connect ECONNREFUSED 127.0.0.1:8080

@startuml
skinparam backgroundColor #ffffff
skinparam Shadowing false
skinparam DefaultFontName Arial
skinparam DefaultFontSize 13
skinparam ArrowColor #475569
skinparam rectangleBorderColor #64748b
skinparam rectangleBackgroundColor #f8fafc
skinparam classBackgroundColor #f8fafc
skinparam classBorderColor #64748b
skinparam interfaceBackgroundColor #ecfdf5
skinparam interfaceBorderColor #10b981
skinparam noteBackgroundColor #fef3c7
skinparam noteBorderColor #d97706
class Client {
+ main()
}
interface Iterator {
+ hasNext(): boolean
+ next(): Object
}
class ConcreteIterator {
- collection: ConcreteCollection
- position: int
+ hasNext(): boolean
+ next(): Object
}
interface Collection {
+ createIterator(): Iterator
}
class ConcreteCollection {
- items: Object[]
+ createIterator(): Iterator
}
Client --> Collection: uses >
Client --> Iterator: uses >
Collection <|-- ConcreteCollection
Iterator <|-- ConcreteIterator
ConcreteCollection ..> ConcreteIterator: creates >
note right of Client::main
// Get collection
collection = new ConcreteCollection()
// Get iterator from collection
iterator = collection.createIterator()
// Iterate through elements
while (iterator.hasNext()) {
item = iterator.next()
// Process item
}
end note
note right of ConcreteCollection::createIterator
return new ConcreteIterator(this)
end note
note "Iterator provides a way to access\nelements sequentially without\nexposing underlying structure" as N1
@enduml
  • Iterator: Interface with methods for traversing a collection
  • ConcreteIterator: Implements the Iterator interface
  • Collection: Interface that creates an Iterator
  • ConcreteCollection: Implements Collection and returns ConcreteIterator
  • Java Collections - Iterator and Iterable interfaces
  • Database Result Sets - Cursor-based record traversal
  • File Systems - Directory tree traversal
  • Social Media Feeds - Infinite scroll pagination

Error generating PlantUML diagram: connect ECONNREFUSED 127.0.0.1:8080

@startuml
skinparam backgroundColor #ffffff
skinparam Shadowing false
skinparam DefaultFontName Arial
skinparam DefaultFontSize 13
skinparam ArrowColor #475569
skinparam rectangleBorderColor #64748b
skinparam rectangleBackgroundColor #f8fafc
skinparam classBackgroundColor #f8fafc
skinparam classBorderColor #64748b
skinparam interfaceBackgroundColor #ecfdf5
skinparam interfaceBorderColor #10b981
skinparam noteBackgroundColor #fef3c7
skinparam noteBorderColor #d97706
class Client {
+ main()
}
class Context {
- state: State
+ setState(State)
+ request()
}
interface State {
+ handle(Context)
}
class ConcreteStateA {
+ handle(Context)
}
class ConcreteStateB {
+ handle(Context)
}
Client --> Context: uses >
Context o--> State
State <|-- ConcreteStateA
State <|-- ConcreteStateB
note right of Context::request
state.handle(this)
end note
note right of ConcreteStateA::handle
// Do something
// May change context's state
context.setState(new ConcreteStateB())
end note
note right of Client::main
// Create context with initial state
initialState = new ConcreteStateA()
context = new Context()
context.setState(initialState)
// Request actions - state changes internally
context.request() // In state A
context.request() // Now in state B
// Client doesn't need to track state changes
end note
note "State transitions are controlled\nby the concrete state classes" as N1
@enduml
  • Context: Maintains a reference to a State object and delegates state-specific behavior
  • State: Interface defining state-specific behavior
  • ConcreteState: Classes that implement specific states’ behavior
  • Order Processing - States: ordered → paid → shipped → delivered
  • Document Workflow - States: draft → review → approved → published
  • Media Players - States: playing, paused, stopped, buffering
  • TCP Connections - States: closed, listen, established, closing
  • Vending Machines - States: idle, selecting, dispensing, out of stock

Error generating PlantUML diagram: connect ECONNREFUSED 127.0.0.1:8080

@startuml
skinparam backgroundColor #ffffff
skinparam Shadowing false
skinparam DefaultFontName Arial
skinparam DefaultFontSize 13
skinparam ArrowColor #475569
skinparam rectangleBorderColor #64748b
skinparam rectangleBackgroundColor #f8fafc
skinparam classBackgroundColor #f8fafc
skinparam classBorderColor #64748b
skinparam interfaceBackgroundColor #ecfdf5
skinparam interfaceBorderColor #10b981
skinparam noteBackgroundColor #fef3c7
skinparam noteBorderColor #d97706
class Client {
+ main()
}
class Request {
- type: String
- content: String
+ getType(): String
+ getContent(): String
}
abstract class Handler {
- successor: Handler
+ setSuccessor(Handler)
+ handleRequest(Request)
}
class ConcreteHandlerA {
+ handleRequest(Request)
}
class ConcreteHandlerB {
+ handleRequest(Request)
}
class ConcreteHandlerC {
+ handleRequest(Request)
}
Client --> Handler: uses >
Client --> Request: creates >
Handler <|-- ConcreteHandlerA
Handler <|-- ConcreteHandlerB
Handler <|-- ConcreteHandlerC
Handler o--> Handler
note right of Handler::handleRequest
if (can handle request)
handle it
else if (successor != null)
successor.handleRequest(request)
end note
note right of Client::main
// Create the chain of handlers
handlerA = new ConcreteHandlerA()
handlerB = new ConcreteHandlerB()
handlerC = new ConcreteHandlerC()
// Build the chain
handlerA.setSuccessor(handlerB)
handlerB.setSuccessor(handlerC)
// Create and process requests
request1 = new Request("Type1", "Process this")
request2 = new Request("Type3", "Handle this")
// Send requests to first handler in chain
handlerA.handleRequest(request1)
handlerA.handleRequest(request2)
end note
note "Each handler decides either to\nprocess the request or pass\nit to the next handler" as N1
@enduml
  • Handler: Abstract class/interface defining the request handling method and successor link
  • ConcreteHandler: Implements the request handling behavior
  • HTTP Middleware - Authentication → logging → compression → response
  • Event Propagation - UI event bubbling in DOM hierarchy
  • Approval Workflows - Employee → manager → director → VP
  • Exception Handling - Try-catch chains in error processing
  • Logging Frameworks - Different log levels (debug, info, warn, error)

Error generating PlantUML diagram: connect ECONNREFUSED 127.0.0.1:8080

@startuml
skinparam backgroundColor #ffffff
skinparam Shadowing false
skinparam DefaultFontName Arial
skinparam DefaultFontSize 13
skinparam ArrowColor #475569
skinparam rectangleBorderColor #64748b
skinparam rectangleBackgroundColor #f8fafc
skinparam classBackgroundColor #f8fafc
skinparam classBorderColor #64748b
skinparam interfaceBackgroundColor #ecfdf5
skinparam interfaceBorderColor #10b981
skinparam noteBackgroundColor #fef3c7
skinparam noteBorderColor #d97706
class Client {
+ main()
}
abstract class AbstractClass {
+ templateMethod()
# {abstract} primitiveOperation1()
# {abstract} primitiveOperation2()
# hook()
}
class ConcreteClassA {
# primitiveOperation1()
# primitiveOperation2()
}
class ConcreteClassB {
# primitiveOperation1()
# primitiveOperation2()
# hook()
}
Client --> ConcreteClassA: uses >
Client --> ConcreteClassB: uses >
AbstractClass <|-- ConcreteClassA
AbstractClass <|-- ConcreteClassB
note right of AbstractClass::templateMethod
primitiveOperation1()
primitiveOperation2()
hook()
// Algorithm structure is fixed
end note
note right of Client::main
// Create concrete implementations
classA = new ConcreteClassA()
classB = new ConcreteClassB()
// Call template method on each
// Steps are defined in subclasses
classA.templateMethod()
classB.templateMethod()
// Client uses the same interface
// but gets different implementations
end note
note "Template Method defines the skeleton\nof an algorithm, with concrete steps\ndefined by subclasses" as N1
@enduml
  • AbstractClass: Defines template methods and abstract operations
  • ConcreteClass: Implements the primitive operations required by the template method
  • Framework Lifecycle - React component lifecycle, Spring bean lifecycle
  • Data Processing - ETL pipelines (extract → transform → load)
  • Document Generation - Report templates with customizable sections
  • Testing Frameworks - setUp → test → tearDown
  • Game Development - Game loop: initialize → update → render

Error generating PlantUML diagram: connect ECONNREFUSED 127.0.0.1:8080

@startuml
skinparam backgroundColor #ffffff
skinparam Shadowing false
skinparam DefaultFontName Arial
skinparam DefaultFontSize 13
skinparam ArrowColor #475569
skinparam rectangleBorderColor #64748b
skinparam rectangleBackgroundColor #f8fafc
skinparam classBackgroundColor #f8fafc
skinparam classBorderColor #64748b
skinparam interfaceBackgroundColor #ecfdf5
skinparam interfaceBorderColor #10b981
skinparam noteBackgroundColor #fef3c7
skinparam noteBorderColor #d97706
class Client {
+ main()
}
class ObjectStructure {
- elements: List<Element>
+ accept(Visitor)
}
interface Visitor {
+ visitConcreteElementA(ConcreteElementA)
+ visitConcreteElementB(ConcreteElementB)
}
class ConcreteVisitor1 {
+ visitConcreteElementA(ConcreteElementA)
+ visitConcreteElementB(ConcreteElementB)
}
class ConcreteVisitor2 {
+ visitConcreteElementA(ConcreteElementA)
+ visitConcreteElementB(ConcreteElementB)
}
interface Element {
+ accept(Visitor)
}
class ConcreteElementA {
+ accept(Visitor)
+ operationA()
}
class ConcreteElementB {
+ accept(Visitor)
+ operationB()
}
Client --> ObjectStructure: uses >
Client --> ConcreteVisitor1: creates >
Client --> ConcreteVisitor2: creates >
ObjectStructure o--> Element
Visitor <|-- ConcreteVisitor1
Visitor <|-- ConcreteVisitor2
Element <|-- ConcreteElementA
Element <|-- ConcreteElementB
note right of ConcreteElementA::accept
visitor.visitConcreteElementA(this)
end note
note right of ObjectStructure::accept
for each element in elements:
element.accept(visitor)
end note
note right of Client::main
// Create object structure with elements
structure = new ObjectStructure()
structure.add(new ConcreteElementA())
structure.add(new ConcreteElementB())
// Create different visitors
visitor1 = new ConcreteVisitor1()
visitor2 = new ConcreteVisitor2()
// Apply visitors to the structure
structure.accept(visitor1)
structure.accept(visitor2)
// Same elements, different operations
end note
note "Visitor separates algorithms\nfrom the objects they operate on" as N1
@enduml
  • Visitor: Interface declaring visit methods for each element type
  • ConcreteVisitor: Implements the visitor interface with specific behavior
  • Element: Interface declaring an accept method
  • ConcreteElement: Implements the element interface
  • Compiler Design - Abstract syntax tree (AST) traversal and analysis
  • Document Processing - XML/HTML DOM operations (rendering, validation, transformation)
  • Report Generation - Different export formats (PDF, HTML, JSON) from same data structure
  • Tax Calculation - Computing taxes for different product types
  • Graphics Rendering - Rendering different shape types

Error generating PlantUML diagram: connect ECONNREFUSED 127.0.0.1:8080

@startuml
skinparam backgroundColor #ffffff
skinparam Shadowing false
skinparam DefaultFontName Arial
skinparam DefaultFontSize 13
skinparam ArrowColor #475569
skinparam rectangleBorderColor #64748b
skinparam rectangleBackgroundColor #f8fafc
skinparam classBackgroundColor #f8fafc
skinparam classBorderColor #64748b
skinparam interfaceBackgroundColor #ecfdf5
skinparam interfaceBorderColor #10b981
skinparam noteBackgroundColor #fef3c7
skinparam noteBorderColor #d97706
class Client {
+ main()
}
interface Mediator {
+ notify(Colleague, Event)
}
class ConcreteMediator {
- colleagueA: ConcreteColleagueA
- colleagueB: ConcreteColleagueB
+ setColleagueA(ConcreteColleagueA)
+ setColleagueB(ConcreteColleagueB)
+ notify(Colleague, Event)
}
abstract class Colleague {
# mediator: Mediator
+ setMediator(Mediator)
}
class ConcreteColleagueA {
+ operationA()
+ receiveFromB()
}
class ConcreteColleagueB {
+ operationB()
+ receiveFromA()
}
Client --> ConcreteMediator: creates >
Client --> ConcreteColleagueA: creates >
Client --> ConcreteColleagueB: creates >
Mediator <|-- ConcreteMediator
Colleague <|-- ConcreteColleagueA
Colleague <|-- ConcreteColleagueB
Colleague o--> Mediator
ConcreteMediator --> ConcreteColleagueA
ConcreteMediator --> ConcreteColleagueB
note right of ConcreteMediator::notify
if (sender == colleagueA && event == "A_EVENT")
colleagueB.receiveFromA()
else if (sender == colleagueB && event == "B_EVENT")
colleagueA.receiveFromB()
end note
note right of Client::main
// Create mediator
mediator = new ConcreteMediator()
// Create colleagues
colleagueA = new ConcreteColleagueA()
colleagueB = new ConcreteColleagueB()
// Register colleagues with mediator
mediator.setColleagueA(colleagueA)
mediator.setColleagueB(colleagueB)
// Set mediator for colleagues
colleagueA.setMediator(mediator)
colleagueB.setMediator(mediator)
// Colleagues communicate through mediator
colleagueA.operationA() // Triggers notification
end note
note "Mediator centralizes complex\ncommunication between objects" as N1
@enduml
  • Mediator: Interface defining communication method between colleagues
  • ConcreteMediator: Implements Mediator and coordinates between colleague objects
  • Colleague: Abstract class for objects that communicate through the mediator
  • ConcreteColleague: Implements Colleague with specific behavior
  • Air Traffic Control - Centralized coordination of aircraft communication
  • Chat Rooms - Server mediates messages between users
  • UI Dialog Boxes - Coordinating interactions between form elements
  • Stock Exchange - Mediating trades between buyers and sellers
  • Smart Home Systems - Central hub coordinating device interactions

Error generating PlantUML diagram: connect ECONNREFUSED 127.0.0.1:8080

@startuml
skinparam backgroundColor #ffffff
skinparam Shadowing false
skinparam DefaultFontName Arial
skinparam DefaultFontSize 13
skinparam ArrowColor #475569
skinparam rectangleBorderColor #64748b
skinparam rectangleBackgroundColor #f8fafc
skinparam classBackgroundColor #f8fafc
skinparam classBorderColor #64748b
skinparam interfaceBackgroundColor #ecfdf5
skinparam interfaceBorderColor #10b981
skinparam noteBackgroundColor #fef3c7
skinparam noteBorderColor #d97706
class Client {
+ main()
}
class Originator {
- state: String
+ setState(String)
+ getState(): String
+ createMemento(): Memento
+ restore(Memento)
}
class Memento {
- state: String
+ getState(): String
}
class Caretaker {
- mementos: List<Memento>
+ addMemento(Memento)
+ getMemento(int): Memento
}
Client --> Originator: uses >
Client --> Caretaker: uses >
Originator --> Memento: creates >
Caretaker o--> Memento: stores >
note right of Originator::createMemento
return new Memento(state)
end note
note right of Originator::restore
setState(memento.getState())
end note
note right of Client::main
// Create originator with initial state
originator = new Originator()
originator.setState("State 1")
System.out.println(originator.getState())
// Create caretaker to track history
caretaker = new Caretaker()
// Save current state
caretaker.addMemento(originator.createMemento())
// Change state and save again
originator.setState("State 2")
System.out.println(originator.getState())
caretaker.addMemento(originator.createMemento())
// Change state once more
originator.setState("State 3")
System.out.println(originator.getState())
// Restore to previous state
originator.restore(caretaker.getMemento(1))
System.out.println("Restored to: " +
originator.getState())
// Restore to first state
originator.restore(caretaker.getMemento(0))
System.out.println("Restored to: " +
originator.getState())
end note
note "Memento captures and externalizes\nan object's state for later restoration" as N1
@enduml
  • Originator: Creates a memento containing its state and uses it to restore state
  • Memento: Stores the internal state of the Originator
  • Caretaker: Keeps track of multiple mementos
  • Text Editors - Undo/redo functionality for document changes
  • Video Games - Save game states, checkpoints
  • Database Systems - Transaction rollback mechanisms
  • Version Control - Saving and restoring file states
  • Drawing Applications - History of drawing operations
  • Form Wizards - Saving progress across multiple steps