Monday, July 27, 2026

Behavioral Design Patterns

 


Mastering Design Patterns in C# and ASP.NET Core

Part 4 – Behavioral Design Patterns

Series: Design Patterns in C# and ASP.NET Core
Category: Behavioral Design Patterns
Level: Intermediate to Advanced
Prerequisites: C#, OOP, SOLID Principles, Interfaces, Dependency Injection, ASP.NET Core


Introduction

We have completed the Creational Design Patterns and Structural Design Patterns sections.

Now we move to the third major category of the Gang of Four (GoF) Design Patterns:

Behavioral Design Patterns

Behavioral Design Patterns focus on how objects communicate with each other, how responsibilities are distributed, and how algorithms or workflows can change without heavily modifying existing code.

While:

  • Creational patterns focus on how objects are created

  • Structural patterns focus on how objects and classes are composed

  • Behavioral patterns focus on how objects communicate and behave

A simple way to remember them:

CREATIONAL
     ↓
How do I create objects?

STRUCTURAL
     ↓
How do I combine objects?

BEHAVIORAL
     ↓
How do objects communicate?

Why Do We Need Behavioral Design Patterns?

Consider a large enterprise application.

A request might travel through:

Controller
   ↓
Authentication
   ↓
Authorization
   ↓
Validation
   ↓
Business Logic
   ↓
Payment
   ↓
Notification
   ↓
Audit

If all of this logic is placed into one class, the application becomes difficult to maintain.

For example:

public void ProcessOrder()
{
    // Authentication

    // Authorization

    // Validation

    // Payment

    // Inventory

    // Notification

    // Logging

    // Audit
}

This creates several problems:

  • Large classes

  • Tight coupling

  • Difficult testing

  • Difficult maintenance

  • Hard-to-change business rules

  • Repeated code

  • Difficult extension

Behavioral patterns help us distribute these responsibilities more effectively.


Behavioral Patterns We Will Cover

Our series will cover the following 11 behavioral patterns:

PartPatternMain Purpose
4.1Chain of ResponsibilityPass a request through a chain of handlers
4.2CommandEncapsulate a request as an object
4.3InterpreterDefine and evaluate a language or expression
4.4IteratorTraverse a collection without exposing its internal structure
4.5MediatorCentralize communication between objects
4.6MementoCapture and restore an object's state
4.7ObserverNotify dependent objects when state changes
4.8StateChange behavior when an object's state changes
4.9StrategySwitch algorithms or behaviors dynamically
4.10Template MethodDefine an algorithm skeleton while allowing steps to vary
4.11VisitorAdd operations to object structures without modifying their classes

4.1 – Chain of Responsibility

Purpose

The Chain of Responsibility Pattern allows a request to pass through a chain of handlers until one of them handles it.

Example

An ASP.NET Core request pipeline is conceptually similar to this idea:

Request
   ↓
Logging
   ↓
Authentication
   ↓
Authorization
   ↓
Validation
   ↓
Controller

Each component can process the request or pass it to the next component.

We'll build examples such as:

  • Approval workflows

  • Validation pipelines

  • Support ticket escalation

  • Authorization

  • Middleware-like processing


4.2 – Command

Purpose

The Command Pattern encapsulates a request as an object.

Instead of:

service.CreateOrder();

we can represent the operation as:

CreateOrderCommand

This is particularly useful in:

  • CQRS

  • Undo/Redo

  • Queues

  • Background jobs

  • Transaction processing

  • Event-driven applications

Example:

Controller
    ↓
Command
    ↓
Command Handler
    ↓
Business Logic

4.3 – Interpreter

Purpose

The Interpreter Pattern defines a representation for a language or grammar and provides an interpreter for that language.

For example:

age > 18

or:

salary > 50000 AND experience > 5

The application can interpret these expressions dynamically.

Potential applications include:

  • Rule engines

  • Search expressions

  • Filtering

  • Query languages

  • Business rules

  • Expression evaluation


4.4 – Iterator

Purpose

The Iterator Pattern provides a standard way to traverse a collection without exposing its internal representation.

C# already provides excellent support for iterator concepts through:

IEnumerable<T>
IEnumerator<T>
yield return

For example:

foreach (var customer in customers)
{
    Console.WriteLine(customer.Name);
}

The client doesn't need to know whether the data is stored in:

  • Array

  • List

  • Tree

  • Database result

  • Custom collection

We'll explore how this pattern works internally.


4.5 – Mediator

Purpose

The Mediator Pattern centralizes communication between objects.

Instead of:

A → B
A → C
A → D
B → C
B → D
C → D

we introduce a mediator:

          A
          |
          |
B ---- Mediator ---- C
          |
          |
          D

This reduces direct dependencies between components.

A very important real-world example is:

ASP.NET Core Controller
        ↓
      Mediator
        ↓
   Command Handler
        ↓
      Service

This pattern is especially relevant when discussing MediatR-style architectures and CQRS.


4.6 – Memento

Purpose

The Memento Pattern captures an object's state so it can be restored later.

The classic example is:

Document
   ↓
Edit
   ↓
Save State
   ↓
Edit Again
   ↓
Undo
   ↓
Restore Previous State

Real-world applications include:

  • Undo/Redo

  • Draft saving

  • Transaction rollback concepts

  • Game checkpoints

  • Editor history


4.7 – Observer

Purpose

The Observer Pattern establishes a one-to-many relationship where multiple objects are notified when another object's state changes.

Example:

                  Order Created
                       ↓
                    Subject
                       |
          +------------+------------+
          ↓            ↓            ↓
       Email        SMS          Audit
       Service      Service       Service

This is highly relevant to:

  • Event-driven systems

  • Notifications

  • Domain events

  • UI updates

  • Messaging systems

C# provides related mechanisms through:

event
Action<T>
IObservable<T>
IObserver<T>

4.8 – State

Purpose

The State Pattern allows an object to change its behavior when its internal state changes.

For example, an order could have:

Pending
   ↓
Confirmed
   ↓
Shipped
   ↓
Delivered

Different operations may be allowed depending on the current state.

Instead of:

if (status == "Pending")
{
    ...
}
else if (status == "Confirmed")
{
    ...
}
else if (status == "Shipped")
{
    ...
}

we can represent each state using a separate class.


4.9 – Strategy

Purpose

The Strategy Pattern allows us to define multiple algorithms and select the appropriate algorithm at runtime.

For example, an e-commerce application may support:

Payment
 ├── Credit Card
 ├── Debit Card
 ├── Bank Transfer
 └── Digital Wallet

Instead of:

if (paymentType == "Card")
{
    // Card
}
else if (paymentType == "Bank")
{
    // Bank
}
else if (paymentType == "Wallet")
{
    // Wallet
}

we can use:

IPaymentStrategy
       ↑
       |
+------+-------+---------+
|              |         |
Card         Bank      Wallet
Strategy     Strategy   Strategy

This is one of the most useful patterns in enterprise C# development.


4.10 – Template Method

Purpose

The Template Method Pattern defines the skeleton of an algorithm while allowing subclasses to customize certain steps.

For example:

Process Application
       ↓
Validate
       ↓
Load Data
       ↓
Process
       ↓
Save
       ↓
Notify

The overall algorithm stays the same, while individual steps can differ.

This pattern is useful when multiple workflows follow the same general process but have different implementations for specific steps.


4.11 – Visitor

Purpose

The Visitor Pattern allows us to add new operations to an object structure without modifying the classes that make up the structure.

It is particularly useful for complex object structures.

For example:

Document
 ├── Paragraph
 ├── Image
 ├── Table
 └── Chart

We might want to perform different operations:

PDF Export
Word Export
Validation
Statistics
Security Scan

Rather than adding all these operations directly into every document class, the Visitor Pattern separates them.


Behavioral Patterns – Enterprise Examples

Let's look at where these patterns could appear in a modern .NET enterprise application.

                         ASP.NET Core API
                                |
                                ↓
                       Chain of Responsibility
                                |
                                ↓
                            Mediator
                                |
                   +------------+------------+
                   ↓                         ↓
                Command                   Query
                   ↓                         ↓
              Handler                    Handler
                   |
                   ↓
                Strategy
                   |
          +--------+--------+
          ↓                 ↓
       Payment          Notification
       Strategy           Strategy
          |
          ↓
         State
          |
    Order Lifecycle

This illustrates how multiple behavioral patterns can work together.


Behavioral Patterns and SOLID Principles

Behavioral patterns often complement SOLID principles.

SOLID PrincipleRelated Behavioral Patterns
Single ResponsibilityCommand, Strategy
Open/ClosedStrategy, State, Visitor
Liskov SubstitutionStrategy, State
Interface SegregationCommand, Strategy
Dependency InversionMediator, Strategy, Observer

These patterns aren't replacements for SOLID.

Instead:

SOLID provides design principles, while Design Patterns provide proven approaches for applying those principles to recurring problems.


Behavioral Patterns in Modern .NET

Modern .NET provides many built-in mechanisms that resemble or implement ideas from behavioral patterns.

Examples include:

Middleware

Conceptually related to:

Chain of Responsibility

Request
 ↓
Middleware
 ↓
Middleware
 ↓
Middleware
 ↓
Endpoint

Delegates and Events

Related to:

Observer

public event EventHandler? OrderCreated;

IEnumerable

Related to:

Iterator

IEnumerable<Customer>

Dependency Injection

Can help implement:

Strategy

services.AddScoped<IPaymentStrategy, CreditCardStrategy>();

CQRS

Frequently uses ideas related to:

Command + Mediator

Command
   ↓
Mediator
   ↓
Handler

Behavioral Design Patterns – Learning Approach

For every pattern in Part 4, we will follow the same structure.

1. Definition

We'll understand exactly what the pattern is and the problem it solves.

2. Problem Statement

We'll first understand the problem before introducing the pattern.

3. Why Do We Need It?

We'll identify the design problems that make the pattern useful.

4. UML Class Diagram

We'll visualize the relationships between:

  • Interfaces

  • Classes

  • Handlers

  • Clients

  • Contexts

5. Complete C# Console Application

Every pattern will include a runnable example.

6. ASP.NET Core Implementation

We'll then transform the concept into an enterprise-style ASP.NET Core example.

7. Real-World Example

We'll use practical examples such as:

  • Banking

  • E-commerce

  • Payment processing

  • Order management

  • Notifications

  • Authentication

  • Microservices

8. Advantages

We'll discuss when the pattern provides value.

9. Disadvantages

We'll also discuss when the pattern should not be used.

10. Best Practices

We'll cover modern C# and ASP.NET Core recommendations.

11. Common Mistakes

We'll identify common implementation problems.

12. Interview Questions

Each article will finish with interview questions ranging from beginner to architect level.


Behavioral Design Patterns – Roadmap

PART 4
│
├── 4.1 Chain of Responsibility
│
├── 4.2 Command
│
├── 4.3 Interpreter
│
├── 4.4 Iterator
│
├── 4.5 Mediator
│
├── 4.6 Memento
│
├── 4.7 Observer
│
├── 4.8 State
│
├── 4.9 Strategy
│
├── 4.10 Template Method
│
└── 4.11 Visitor

Complete Design Patterns Series Roadmap

At this stage, our complete series looks like this:

Design Patterns in C# and ASP.NET Core
│
├── Part 1 – Introduction
│
├── Part 2 – Creational Patterns
│   ├── Singleton
│   ├── Factory Method
│   ├── Abstract Factory
│   ├── Builder
│   └── Prototype
│
├── Part 3 – Structural Patterns
│   ├── Adapter
│   ├── Bridge
│   ├── Composite
│   ├── Decorator
│   ├── Facade
│   ├── Flyweight
│   └── Proxy
│
└── Part 4 – Behavioral Patterns
    ├── Chain of Responsibility
    ├── Command
    ├── Interpreter
    ├── Iterator
    ├── Mediator
    ├── Memento
    ├── Observer
    ├── State
    ├── Strategy
    ├── Template Method
    └── Visitor

Final Thoughts

Behavioral Design Patterns are particularly important when developing large-scale .NET applications, because enterprise systems frequently contain complex workflows, business rules, communication between services, event handling, and changing algorithms.

The most important thing is not to memorize all 11 patterns.

Instead, learn to recognize the problem:

"What kind of communication or responsibility problem am I trying to solve?"

Then select the appropriate pattern.

For example:

Request needs multiple handlers?
        ↓
Chain of Responsibility

Operation should be represented as an object?
        ↓
Command

Objects need centralized communication?
        ↓
Mediator

Objects need notifications?
        ↓
Observer

Behavior changes according to state?
        ↓
State

Algorithm needs to be interchangeable?
        ↓
Strategy

Same workflow, customizable steps?
        ↓
Template Method

Need to add operations without modifying object structure?
        ↓
Visitor

This problem-first approach is much more valuable in real-world development and .NET architecture interviews than simply memorizing pattern definitions.


🚀 Next Article

Part 4.1 – Chain of Responsibility Design Pattern

In the next article, we'll start with the Chain of Responsibility Design Pattern, covering:

  • What is the Chain of Responsibility Pattern?

  • Why do we need it?

  • Request and Handler concepts

  • Handler chains

  • UML Class Diagram

  • Complete C# Console Application

  • ASP.NET Core Middleware example

  • Banking approval workflow

  • Exception handling pipeline

  • Validation pipeline

  • Authentication and authorization pipeline

  • Real-world enterprise examples

  • Advantages and disadvantages

  • Best practices

  • Common mistakes

  • Chain of Responsibility vs Middleware

  • Chain of Responsibility vs Decorator

  • Interview questions

The next article will be particularly useful for understanding how ASP.NET Core Middleware works internally and how request-processing pipelines can be designed using the Chain of Responsibility concept.

No comments:

Don't Copy

Protected by Copyscape Online Plagiarism Checker