badge icon

This article was automatically translated from the original Turkish version.

Blog
Blog
Avatar
AuthorSinan TuranNovember 29, 2025 at 8:14 AM

Behavioral Design Patterns

Quote

1. Chain of Responsibility (Responsibility Chain)

The Chain of Responsibility design pattern links objects in a chain to dynamically determine which object will handle a request. In this chain, each object either processes the request or passes it to the next object in the chain.

-> When to Use?

  • When you want to decouple the sender of a request from its processor,
  • When multiple objects can handle a request but the handler is not known until runtime,

And when the order or number of objects in the chain can be changed.

-> Real-Life Analogy

Consider a customer support system: a user first interacts with a chatbot; if the issue is not resolved, it is passed to a human support agent; if still unresolved, it is escalated to a supervisor. This system is a perfect example of a responsibility chain.

-> Code Example

-> Advantages

The Chain of Responsibility design pattern draws attention by eliminating the dependency between the sender and the object that processes the request. In this structure, objects form a chain where each object has the ability to either process the request itself or forward it to the next object in the chain. This allows the chain to be easily extended and new processing steps to be integrated into the existing structure. Moreover, from the client’s perspective, it is irrelevant which object ultimately processes the request; what matters is that the request is handled by an appropriate object in the chain.

-> Disadvantages

The Chain of Responsibility design pattern also has potential disadvantages. Each request may potentially traverse all objects in the chain, which can lead to performance costs, especially in long chains. Additionally, whether a suitable object exists in the chain to handle a specific request is only determined at runtime. This may result in some requests never being processed.

2. Command (Command)

The Command design pattern encapsulates a request as an object. This allows us to queue, log, or even undo requests. Additionally, it establishes loose coupling between the client and the object performing the action.

-> When to Use

  • When requests need to be stored in a queue, ordered, or logged,
  • When undo operations are required,
  • When operations need to be scheduled for later execution,
  • When tight coupling between sender and receiver is not desired.

-> Real-Life Analogy

Consider a waiter in a restaurant who takes orders from customers and delivers them to the kitchen. The waiter only receives the order (command) but does not know what will be cooked—the chef knows (receiver). The waiter and chef do not need to know each other’s details.

-> Code Example

-> Advantages

The Command design pattern enables operations to be encapsulated as objects, allowing commands to be logged and undone. This makes it possible to maintain a record of performed actions and revert to previous states when needed. Additionally, commands can be queued for execution in a specific order or at a scheduled time, simplifying the management of complex workflows. A key advantage is that it clearly separates the sender that triggers the command from the receiver that executes it, significantly reducing the dependency between these two components. This reduces coupling between different parts of the system, resulting in a more flexible and maintainable structure.

-> Disadvantages

The Command design pattern also has some disadvantages. For each distinct operation, a separate command class may need to be created, which can lead to a significant increase in the number of command classes over time. Consequently, in systems with many different types of operations, this can increase overall structural complexity and make management more difficult.

3. Iterator (Iterator)

The Iterator design pattern enables traversal over the elements of a collection without knowing the internal structure of the collection. This makes it easier to access structures such as lists, arrays, or trees from the outside.

 -> When to Use?

  • When you want to traverse complex data structures without knowing their internal details,
  • When you want to traverse different types of collections in a similar way,
  • When you want to encapsulate the collection’s traversal algorithm as an object.

-> Real-Life Analogy

Consider a music player. You can navigate to the previous or next song in a playlist without needing to know how the playlist is stored internally. The iterator simply provides you with the ability to move from song to song.

-> Code Example

-> Advantages

The Iterator design pattern fundamentally provides access to and traversal of different collection structures independently of their internal workings. This pattern allows a standard interface to be defined for iterating over various data structures such as lists, sets, and trees. Moreover, the iterator pattern enables the separation of different traversal algorithms (e.g., depth-first, breadth-first) from the concrete collection structure, allowing customized traversal strategies to be applied according to specific needs. Finally, this pattern significantly reduces the amount of code needed to perform repetitive traversal operations across different collections, resulting in more abstract, readable, and reusable code.

-> Disadvantages

The Iterator design pattern also has potential disadvantages in certain scenarios. In particular, when a copy of the collection must be created during iteration, this can introduce additional performance overhead. Additionally, supporting multiple iteration behaviors may require the creation of several concrete iterator classes, which can increase the total number of classes in the system and thereby affect overall complexity.

4. Interpreter (Interpreter)

The Interpreter design pattern uses objects to represent the grammar (rules) of a language, enabling the interpretation of sentences (expressions). In other words, this pattern allows you to write your own mini programming language and interpret and execute it.

-> When to Use?

  • When you need to interpret expressions of a language with a defined grammar,
  • In cases involving small, simple, and repetitive interpretation rules,
  • For interpreting mathematical expressions, Boolean expressions, or custom command languages.

-> Real-Life Analogy

Consider a simple calculator. It must interpret an expression like "5 + 3 - 2" and produce a result. Each number and operator is a symbol. The Interpreter pattern parses these symbols to compute the result.

-> Code Example

This example is based on a simple language that interprets mathematical expressions (e.g., "1 + 2").

-> Advantages

The Interpreter design pattern is based on representing grammar rules through objects. This approach directly reflects the grammar structure in code, enabling easy extension of the language and seamless integration of new grammar expressions into the system. This makes the interpreter pattern particularly suitable for developing domain-specific languages (DSLs). DSLs are limited-scope languages optimized to express a specific problem domain, and the interpreter pattern provides an effective tool for modeling their syntactic and semantic structure.

-> Disadvantages

The Interpreter design pattern also has potential disadvantages. In particular, when dealing with complex grammar rules, a separate class may need to be created for each rule or rule combination. This can significantly increase the number of classes in the system and lead to management challenges. Additionally, because the interpretation process may require creating and managing many small objects, it can cause performance issues in certain scenarios.

5. Mediator (Mediator)

The Mediator design pattern prevents direct communication between objects and instead facilitates communication through a central object. This reduces dependencies between components and simplifies system maintenance.

-> When to Use

  • When there are many complex interactions between objects,
  • When a component needs to communicate with others without knowing their details,
  • When you want to reduce dependencies and create a more readable structure.

-> Real-Life Analogy

Consider the control tower in an airport. It ensures that all pilots can land and take off without directly interacting with each other. Pilots communicate not with each other, but through the control tower.

-> Code Example

In this example, different users communicate via a chat room (ChatRoom) using a mediator.

-> Advantages

The Mediator design pattern aims to eliminate tight coupling between different objects in the system by preventing direct communication. Instead, it manages all complex communication flows through a central mediator object. This consolidates multiple and complex communication paths into a single point, simplifying them. As a result, when changes are needed in the behavior or communication of any object, they are made only on the mediator, reducing the likelihood of affecting other objects and making maintenance easier.

-> Disadvantages

Alongside its advantages, the Mediator design pattern has potential risks. One of the most notable is that the mediator class, by managing all communication in the system, may accumulate excessive responsibilities and evolve into the "God Object" anti-pattern. In this case, the mediator class can grow excessively large and become difficult to maintain. Additionally, because complex communication logic is concentrated within the mediator, it may become overly complex and hard to understand.

6. Memento (Memento)

The Memento pattern is used to save a previous state of an object and later restore it. This pattern provides undo functionality without exposing the object’s internal structure.

-> When to Use?

  • When you want to allow users to undo their actions,
  • When you need to store past states of an object,
  • When you want to protect the object’s internal state from direct external access.

-> Real-Life Analogy

In a text editor (e.g., Word), your writing is periodically saved. When you click "Undo," you return to a previously saved state. This is exactly what the Memento pattern does.

-> Code Example

In this example, an Originator class holds the state, a Memento class stores it, and a Caretaker class manages the stored states.

-> Advantages

The Memento design pattern enables capturing and storing an object’s internal state without exposing it directly to other objects outside the object itself. This allows the object to return to a previous state using the stored state information. It particularly facilitates the easy implementation of undo and redo functionalities, playing a crucial role in interactive applications. By preserving the object’s internal structure, it prevents external interference and maintains the object’s integrity.

-> Disadvantages

Alongside its benefits, the Memento design pattern has potential costs to consider. In scenarios where many memento objects representing past states must be stored in memory, the application’s memory consumption can increase significantly. Additionally, frequently saving states of large objects can negatively impact performance due to the overhead of copying and storage. Therefore, when using the memento pattern, careful management of the balance between the number and frequency of stored states and memory and performance is essential.

7. Observer (Observer)

The Observer pattern is used to automatically notify other objects of changes occurring in one object. This pattern is based on the publisher-subscriber model.

-> When to Use

  • When you need to establish one-to-many relationships between objects,
  • When other objects must be automatically notified of changes in one object,
  • When components such as user interfaces need to remain up to date.

-> Real-Life Analogy

Imagine subscribing to a news bulletin. When a new article is published, you receive an email. The news publisher does not contact you directly; it simply adds the news to the system. If your email address is registered, you automatically receive the notification. This is the Observer pattern.

-> Code Example

In this example, a Subject object maintains a list of observers. Whenever a change occurs, all observers are notified.

-> Advantages

The Observer design pattern establishes loose coupling between components in the system by automatically notifying subscribed objects (observers) of changes in the subject object. This structure allows new observers to be easily added to the system while minimizing dependency between the subject and observers. Additionally, because changes in the subject’s state are immediately propagated to observers, real-time synchronization is achieved. This feature provides significant advantages in areas such as user interfaces, event-driven systems, and distributed applications.

-> Disadvantages

The Observer design pattern also has potential disadvantages. When a large number of observers are subscribed to a subject, every change in the subject’s state triggers individual notifications to all observers. This can lead to performance issues, especially in scenarios where notification operations are expensive. Additionally, the order in which observers receive notifications is typically not guaranteed. In some cases, observers may need to receive notifications in a specific sequence, but the nature of the observer pattern makes controlling this order difficult.

8. State (State)

The State pattern allows an object to change its behavior based on its internal state. It behaves as if the object’s class were changed at runtime.

-> When to Use

  • When an object’s behavior changes according to its internal state,
  • When long and complex if-else or switch statements control behavior based on conditions,
  • When you want each state to have its own class and behavior.

-> Real-Life Analogy

Consider a turnstile. Initially, it is in a locked state. When you insert a token, it becomes unlocked. If you insert another token while unlocked, it returns the token. After passage, it locks again. Each state determines the turnstile’s behavior.

-> Code Example

In this example, a Context class represents the current state (State) and delegates behavior to it.

-> Advantages

The State design pattern allows an object to change its behavior based on its internal state. This pattern defines each possible state as a separate class and maintains a reference to the object representing the current state. When the object’s state changes, this reference points to a different state object, thereby changing the object’s behavior. This approach helps eliminate nested and hard-to-read if-else blocks in applications with complex, condition-dependent behavior. As a result, the state pattern provides a clearer, more organized, and more understandable structure, making code maintenance and extension easier.

-> Disadvantages

Alongside its advantages, the State design pattern has some potential challenges. In scenarios where an object can have many different states, a separate class must be defined for each state, which can significantly increase the total number of classes in the system. This can increase the overall complexity of the project and make management more difficult. Additionally, ensuring that transitions between different states are managed correctly and consistently requires careful planning and implementation. Poorly managed state transitions can lead to unexpected behaviors and errors.

9. Strategy (Strategy)

The Strategy pattern defines various versions of an algorithm and makes them interchangeable. Strategies are interchangeable and can be selected dynamically at runtime.

-> When to Use?

  • When there are classes that perform the same task but use different algorithms,
  • When different behaviors are selected using conditions (if-else, switch) in code,
  • When behavior needs to be changed at runtime.

-> Real-Life Analogy

Consider a navigation app. It offers users options such as "Shortest Route," "Low-Traffic Route," or "Use Toll Road." Each option represents a different strategy.

-> Code Example

In this example, a Context class receives behavior from a strategy interface and executes it.

-> Advantages

The Strategy design pattern defines a family of algorithms, encapsulates each algorithm in a separate class, and makes them interchangeable. This allows different algorithms to be developed and managed independently without affecting other parts of the system. This significantly simplifies code maintenance because changes to one algorithm do not impact other algorithms or the client code using them. Moreover, which algorithm is used can be determined or changed dynamically at runtime, providing great flexibility to the system. For example, different sorting algorithms or payment methods can be easily implemented and swapped using the strategy pattern.

-> Disadvantages

While the Strategy design pattern offers flexibility and ease of maintenance, it has some potential disadvantages. Since a separate class must be created for each distinct algorithm, the total number of classes in the system can increase. This can increase the complexity of the project, especially when many different strategies are required. Additionally, the client code responsible for deciding which strategy to use and when must be aware of the available strategies and select and configure the appropriate one. This can create some dependency between the client and the strategy classes.

10. Template Method (Template Method)

The Template Method pattern defines the skeleton of an algorithm in a superclass and allows subclasses to customize certain steps. This preserves the algorithm’s structure while permitting specific steps to be modified in subclasses.

 -> When to Use?

  • When the steps of an algorithm are fixed but some steps can be customized,
  • When you want to reduce code duplication and define the algorithm flow in a central location.

-> Real-Life Analogy

Consider the process of making tea or coffee:

  1. Boil water,
  2. Brew the ingredient,
  3. Pour into cups,
  4. Optionally add sugar or milk.

The order of these steps is fixed (template), but the "brewing" step varies depending on the ingredient (tea or coffee).

-> Code Example

In this example, the beverage preparation process is defined as a general template, and subclasses customize certain steps.

-> Advantages

The Template Method design pattern defines the skeleton of an algorithm in a superclass and leaves certain steps to be implemented by subclasses. This preserves the overall structure of the algorithm while allowing subclasses to provide their own specific implementations. This approach significantly reduces code duplication because common parts of the algorithm are defined in one place and reused by different subclasses. Moreover, mechanisms such as "hook methods" defined in the template method provide flexibility for subclasses to intervene at specific points in the algorithm and customize behavior. This allows the algorithm to adapt to different needs without altering its overall structure.

-> Disadvantages

Alongside its benefits, the Template Method design pattern has some limitations. Subclasses must understand which steps of the algorithm to implement and how these steps interact with the overall flow. This imposes a certain information burden on subclasses. Additionally, if some steps in the template method are not declared as abstract and have concrete implementations in the superclass, the flexibility of subclasses to customize those steps is limited. In such cases, subclasses may find themselves constrained when attempting to modify certain parts of the algorithm.

11. Visitor (Visitor)

The Visitor pattern is used to define new operations on elements of an object structure (such as a tree, collection, or file system) without modifying the classes of those elements.

-> When to Use?

  • When you want to add new operations without altering the object structure,
  • When object classes are closed but operations to be applied to them must be open (Open/Closed Principle),
  • When different types of operations need to be performed on objects with the same structure.

-> Real-Life Analogy

Consider baggage inspection at customs. Each bag may be of a different type (handbag, suitcase, crate), but the customs officer (visitor) applies a different procedure to each type.

The officer opens the suitcase, inspects the handbag manually, and scans the crate with an X-ray.

The officer "visits" each bag without knowing its type and performs the appropriate action.

-> Code Example

In this example, various Shape types are exported to an XML file.

The export operation is performed through the Visitor class without modifying the shape classes.

-> Advantages

The Visitor design pattern enables the definition and addition of new operations on elements of an object structure (such as a tree or collection) without modifying the classes of those elements. This means that when new functionality is needed, existing object classes remain unchanged, and modifications are centrally managed through visitor classes. Additionally, the visitor pattern simplifies performing the same logical operation across a structure composed of different object types. By defining a separate visitor method for each object type, the operation can be consistently applied across the entire structure.

-> Disadvantages

Alongside its advantages, the Visitor design pattern has important disadvantages. When a new element type is added to the object structure, all existing visitor classes must be updated to handle the new element. This increases maintenance costs, especially in systems where new elements are frequently added. Additionally, the bidirectional interaction mechanism between the visitor and the visited element can be complex to design and understand initially. The required interfaces and methods for the visitor to operate on the element and for the element to accept the visitor must be carefully designed.

Blog Operations

Contents

  • 1. Chain of Responsibility (Responsibility Chain)

    • -> When to Use?

    • -> Real-Life Analogy

    • -> Code Example

    • -> Advantages

    • -> Disadvantages

  • 2. Command (Command)

    • -> When to Use

    • -> Real-Life Analogy

    • -> Code Example

    • -> Advantages

    • -> Disadvantages

  • 3. Iterator (Iterator)

    • -> When to Use?

    • -> Real-Life Analogy

    • -> Code Example

    • -> Advantages

    • -> Disadvantages

  • 4. Interpreter (Interpreter)

    • -> When to Use?

    • -> Real-Life Analogy

    • -> Code Example

    • -> Advantages

    • -> Disadvantages

  • 5. Mediator (Mediator)

    • -> When to Use

    • -> Real-Life Analogy

    • -> Code Example

    • -> Advantages

    • -> Disadvantages

  • 6. Memento (Memento)

    • -> When to Use?

    • -> Real-Life Analogy

    • -> Code Example

    • -> Advantages

    • -> Disadvantages

  • 7. Observer (Observer)

    • -> When to Use

    • -> Real-Life Analogy

    • -> Code Example

    • -> Advantages

    • -> Disadvantages

  • 8. State (State)

    • -> When to Use

    • -> Real-Life Analogy

    • -> Code Example

    • -> Advantages

    • -> Disadvantages

  • 9. Strategy (Strategy)

    • -> When to Use?

    • -> Real-Life Analogy

    • -> Code Example

    • -> Advantages

    • -> Disadvantages

  • 10. Template Method (Template Method)

    • -> When to Use?

    • -> Real-Life Analogy

    • -> Code Example

    • -> Advantages

    • -> Disadvantages

  • 11. Visitor (Visitor)

    • -> When to Use?

    • -> Real-Life Analogy

    • -> Code Example

    • -> Advantages

    • -> Disadvantages

Ask to Küre