Interview Q&A

Technical interview questions with detailed answers—organized by course, like Dot Net Tutorials interview sections. Original content for Toolliyo Academy.

By tech stack (from PDF library)

Design Patterns in C# · CLR & types

Short answer: CLR & types is essential when working with Design Patterns in C#. Interviewers want to hear clear definitions, trade-offs, and a concise example from your experience.

How to structure your answer

  1. Define the concept in one or two sentences.
  2. Explain how it applies in Design Patterns in C# projects.
  3. Give an example from work, internships, or a personal project.
  4. Mention trade-offs—what you gain and what you sacrifice.

Example talking points

  • What problem does CLR & types solve?
  • What tools or APIs do you use (.NET ecosystem)?
  • How do you test or monitor this area?

Tip: Keep answers under 90 seconds unless the interviewer asks for depth. Practice aloud on Toolliyo before your mock interview.

Permalink

Design Patterns in C# · ASP.NET Core

Short answer: ASP.NET Core is essential when working with Design Patterns in C#. Interviewers want to hear clear definitions, trade-offs, and a concise example from your experience.

How to structure your answer

  1. Define the concept in one or two sentences.
  2. Explain how it applies in Design Patterns in C# projects.
  3. Give an example from work, internships, or a personal project.
  4. Mention trade-offs—what you gain and what you sacrifice.

Example talking points

  • What problem does ASP.NET Core solve?
  • What tools or APIs do you use (.NET ecosystem)?
  • How do you test or monitor this area?

Tip: Keep answers under 90 seconds unless the interviewer asks for depth. Practice aloud on Toolliyo before your mock interview.

Permalink

Design Patterns in C# · EF Core

Short answer: EF Core is essential when working with Design Patterns in C#. Interviewers want to hear clear definitions, trade-offs, and a concise example from your experience.

How to structure your answer

  1. Define the concept in one or two sentences.
  2. Explain how it applies in Design Patterns in C# projects.
  3. Give an example from work, internships, or a personal project.
  4. Mention trade-offs—what you gain and what you sacrifice.

Example talking points

  • What problem does EF Core solve?
  • What tools or APIs do you use (.NET ecosystem)?
  • How do you test or monitor this area?

Tip: Keep answers under 90 seconds unless the interviewer asks for depth. Practice aloud on Toolliyo before your mock interview.

Permalink

Design Patterns in C# · Security

Short answer: Security is essential when working with Design Patterns in C#. Interviewers want to hear clear definitions, trade-offs, and a concise example from your experience.

How to structure your answer

  1. Define the concept in one or two sentences.
  2. Explain how it applies in Design Patterns in C# projects.
  3. Give an example from work, internships, or a personal project.
  4. Mention trade-offs—what you gain and what you sacrifice.

Example talking points

  • What problem does Security solve?
  • What tools or APIs do you use (.NET ecosystem)?
  • How do you test or monitor this area?

Tip: Keep answers under 90 seconds unless the interviewer asks for depth. Practice aloud on Toolliyo before your mock interview.

Permalink

Design Patterns in C# · Testing

Short answer: Testing is essential when working with Design Patterns in C#. Interviewers want to hear clear definitions, trade-offs, and a concise example from your experience.

How to structure your answer

  1. Define the concept in one or two sentences.
  2. Explain how it applies in Design Patterns in C# projects.
  3. Give an example from work, internships, or a personal project.
  4. Mention trade-offs—what you gain and what you sacrifice.

Example talking points

  • What problem does Testing solve?
  • What tools or APIs do you use (.NET ecosystem)?
  • How do you test or monitor this area?

Tip: Keep answers under 90 seconds unless the interviewer asks for depth. Practice aloud on Toolliyo before your mock interview.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Singleton pattern ensures a class has only one instance and provides a global point of

access to it. It’s commonly used when exactly one object is needed to coordinate actions

across the system, such as configuration settings, logging, or caching.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Review the concept and prepare a concise verbal explanation with a real project example.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

One common thread-safe implementation uses lazy initialization with Lazy<T>:

public sealed class Singleton

private static readonly Lazy<Singleton> instance = new

Lazy<Singleton>(() => new Singleton());

private Singleton() { }

public static Singleton Instance => instance.Value;

This approach ensures thread safety and lazy initialization without locks.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Review the concept and prepare a concise verbal explanation with a real project example.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Global state: Singleton can lead to hidden dependencies and make testing difficult.
  • Tight coupling: Other classes depend on the Singleton instance, reducing flexibility.
  • Concurrency issues: If not implemented thread-safe, it can cause race conditions.
  • Resource contention: Singleton might become a bottleneck if overused in

concurrent environments.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Review the concept and prepare a concise verbal explanation with a real project example.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

container, though generally discouraged.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Singletons can hinder unit testing because they introduce global state, making tests

dependent on a shared instance. This can cause tests to be flaky or order-dependent. To

mitigate this, use interfaces and dependency injection, or design the Singleton to allow

resetting its state for tests.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Eager Initialization: The Singleton instance is created at the time of class loading.

It's simple but can waste resources if the instance is never used.

  • Lazy Initialization: The instance is created only when it is first accessed. It saves

resources but requires careful implementation for thread safety.

Factory pattern Q&A

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Factory pattern is a creational design pattern that provides an interface for creating

objects but allows subclasses or implementations to decide which class to instantiate. It’s

used to encapsulate object creation, promoting loose coupling and flexibility when the exact

types of objects aren’t known until runtime.

Use case: When a class can’t anticipate the class of objects it needs to create, or when you

want to delegate responsibility for object creation to subclasses.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Factory Method: Defines an interface for creating an object but lets subclasses

decide which class to instantiate. It uses inheritance and relies on subclass

overriding.

  • Abstract Factory: Provides an interface to create families of related or dependent

objects without specifying their concrete classes. It uses composition and is useful

when you need to create multiple related objects together.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

A simple example of Factory Method:

// Product interface

public interface IAnimal

void Speak();

// Concrete Products

public class Dog : IAnimal

public void Speak() => Console.WriteLine("Woof");

public class Cat : IAnimal

public void Speak() => Console.WriteLine("Meow");

// Factory

public class AnimalFactory

public static IAnimal CreateAnimal(string animalType)

return animalType.ToLower() switch

"dog" => new Dog(),

"cat" => new Cat(),

_ => throw new ArgumentException("Invalid animal type")

Usage:

var dog = AnimalFactory.CreateAnimal("dog");

dog.Speak(); // Outputs: Woof

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Encapsulates object creation: Decouples client code from concrete classes.
  • Promotes code reuse: Centralizes object creation logic.
  • Enhances maintainability: Adding new types requires minimal changes to existing

code.

  • Supports polymorphism: Clients work with interfaces or base classes rather than

concrete types.

  • Improves testability: Can easily mock or swap factory implementations.
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Yes! Factory pattern can complement Dependency Injection (DI) by abstracting complex

object creation logic, especially when the creation involves runtime parameters or complex

setup that DI containers can’t handle easily.

Example: Imagine a service that needs different data repositories based on a runtime

parameter.

public interface IRepository { void Save(); }

public class SqlRepository : IRepository { public void Save() =>

Console.WriteLine("Saving to SQL DB"); }

public class InMemoryRepository : IRepository { public void Save()

=> Console.WriteLine("Saving in Memory"); }

public interface IRepositoryFactory

IRepository CreateRepository(string repoType);

public class RepositoryFactory : IRepositoryFactory

public IRepository CreateRepository(string repoType)

return repoType.ToLower() switch

"sql" => new SqlRepository(),

"memory" => new InMemoryRepository(),

_ => throw new ArgumentException("Invalid repository

type")

// Consumer class with DI

public class Service

private readonly IRepositoryFactory _repositoryFactory;

public Service(IRepositoryFactory repositoryFactory)

_repositoryFactory = repositoryFactory;

public void SaveData(string repoType)

var repo = _repositoryFactory.CreateRepository(repoType);

repo.Save();

Here, DI injects the IRepositoryFactory while the factory manages object creation

based on runtime input. This promotes loose coupling and flexibility.

Strategy Design Pattern

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Strategy pattern is a behavioral design pattern that defines a family of algorithms,

encapsulates each one, and makes them interchangeable at runtime.

It allows the algorithm to vary independently from clients that use it.

Problem it solves:

Avoids large if-else or switch statements when selecting behavior and promotes

flexibility by decoupling the algorithm from the client using it.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Example: Payment strategy selection

// Strategy Interface

public interface IPaymentStrategy

void Pay(decimal amount);

// Concrete Strategies

public class CreditCardPayment : IPaymentStrategy

public void Pay(decimal amount) => Console.WriteLine($"Paid

{amount} using Credit Card");

public class PayPalPayment : IPaymentStrategy

public void Pay(decimal amount) => Console.WriteLine($"Paid

{amount} using PayPal");

// Context

public class PaymentContext

private IPaymentStrategy _paymentStrategy;

public PaymentContext(IPaymentStrategy paymentStrategy)

_paymentStrategy = paymentStrategy;

public void ExecutePayment(decimal amount)

_paymentStrategy.Pay(amount);

Usage:

var context = new PaymentContext(new PayPalPayment());

context.ExecutePayment(200); // Outputs: Paid 200 using PayPal

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Payment gateways (Credit Card, PayPal, UPI, etc.)
  • Sorting algorithms (QuickSort, MergeSort, BubbleSort)
  • Authentication strategies (OAuth, JWT, LDAP)
  • Compression algorithms (ZIP, RAR, TAR)
  • Loggers (FileLogger, ConsoleLogger, DatabaseLogger)
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

It promotes the Open/Closed Principle by allowing you to add new strategies (algorithms

or behaviors) without modifying the existing code.

The context class uses an interface for the strategy, so new behavior can be added just by

creating a new class that implements the interface—no need to touch existing logic.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Aspect Strategy Pattern State Pattern

Purpose Encapsulates interchangeable

behaviors (algorithms).

Encapsulates states and transitions

between them.

Client

Control

Client decides which strategy to use. Object changes its own state

internally.

Behavior

Switch

Switched externally (e.g., passed as

a parameter).

Switched internally (e.g., via

method call).

Example Payment method selection. Document lifecycle (Draft →

Published → Archived).

Repository Design Pattern

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Repository pattern abstracts the data access layer from the business logic by providing

a collection-like interface to access domain objects.

It helps keep data access logic centralized and makes the codebase easier to maintain,

test, and swap out data sources (e.g., switching from EF Core to Dapper or an API).

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Here's a basic example:

// Entity

public class Product

public int Id { get; set; }

public string Name { get; set; }

// Generic Repository Interface

public interface IRepository<T> where T : class

Task<IEnumerable<T>> GetAllAsync();

Task<T> GetByIdAsync(int id);

Task AddAsync(T entity);

void Update(T entity);

void Delete(T entity);

Task SaveAsync();

// EF Core implementation

public class Repository<T> : IRepository<T> where T : class

private readonly DbContext _context;

private readonly DbSet<T> _dbSet;

public Repository(DbContext context)

_context = context;

_dbSet = context.Set<T>();

public async Task<IEnumerable<T>> GetAllAsync() => await

_dbSet.ToListAsync();

public async Task<T> GetByIdAsync(int id) => await

_dbSet.FindAsync(id);

public async Task AddAsync(T entity) => await

_dbSet.AddAsync(entity);

public void Update(T entity) => _dbSet.Update(entity);

public void Delete(T entity) => _dbSet.Remove(entity);

public async Task SaveAsync() => await

_context.SaveChangesAsync();

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Separation of concerns between business and data access layers
  • Improved testability (can mock repositories)
  • Centralized query logic for maintainability
  • Easier to switch persistence implementations
  • Promotes cleaner and more organized code
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Add custom methods in a specialized repository interface (e.g.,

IProductRepository)

  • Use Specification pattern or LINQ expressions
  • Inject DbContext into repository if needed for advanced queries
  • Optionally, break out complex queries into Query objects or services

public interface IProductRepository : IRepository<Product>

Task<IEnumerable<Product>> GetProductsWithLowStockAsync(int

threshold);

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Over-abstraction: Can add unnecessary complexity for simple apps.
  • Duplication: May duplicate what EF Core already provides (since EF is already a

repository/unit-of-work pattern).

  • Hides EF Core features: May obscure advanced capabilities like eager loading or

projections.

  • Extra boilerplate: Especially with generic repositories, which may not add much

value.

Unit of Work

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Unit of Work pattern is a design pattern used to maintain a list of operations to be

performed within a single transaction. It ensures that all operations either succeed or fail

together, providing consistency and managing changes to multiple business objects during a

transaction. It coordinates the writing out of changes and resolves potential concurrency

issues.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Repository pattern abstracts the data access layer, providing a simplified interface to

data operations. The Unit of Work pattern complements it by managing multiple repositories

and ensuring that all changes made through these repositories are committed in a single

transaction. This combination separates concerns, promotes clean architecture, and

maintains transactional integrity across multiple operations.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

In a .NET application (especially using Entity Framework), the Unit of Work is typically

implemented around the DbContext, as it already tracks changes and handles

transactions. Here's a simplified example:

// IUnitOfWork.cs

public interface IUnitOfWork : IDisposable

IProductRepository Products { get; }

ICustomerRepository Customers { get; }

int Complete();

// UnitOfWork.cs

public class UnitOfWork : IUnitOfWork

private readonly AppDbContext _context;

public IProductRepository Products { get; private set; }

public ICustomerRepository Customers { get; private set; }

public UnitOfWork(AppDbContext context)

_context = context;

Products = new ProductRepository(_context);

Customers = new CustomerRepository(_context);

public int Complete()

return _context.SaveChanges(); // All changes in one

transaction

public void Dispose()

_context.Dispose();

Then register it using Dependency Injection in Startup.cs or Program.cs:

services.AddScoped<IUnitOfWork, UnitOfWork>();

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Transactional consistency: All changes across repositories are saved in a single

transaction.

  • Centralized commit: All changes are committed through one method

(Complete()), improving control and readability.

  • Reduced code duplication: Prevents repeated save logic across repositories.
  • Improved testability: Enables better unit testing by mocking a single Unit of Work

instead of multiple repositories.

  • Change tracking: Ensures that only modified entities are persisted, reducing

unnecessary database operations.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Yes, combining Unit of Work with Dependency Injection (DI) is a best practice in modern

.NET applications. DI allows the Unit of Work to be injected into services or controllers,

managing its lifecycle effectively. This improves modularity, promotes loose coupling, and

makes the application easier to maintain and test.

Example using constructor injection in a service:

public class OrderService

private readonly IUnitOfWork _unitOfWork;

public OrderService(IUnitOfWork unitOfWork)

_unitOfWork = unitOfWork;

public void PlaceOrder(Order order)

_unitOfWork.Orders.Add(order);

_unitOfWork.Complete();

Dependency Injection (DI)

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Dependency Injection (DI) is a design pattern that allows an object to receive its

dependencies from an external source rather than creating them itself. This promotes loose

coupling, enhances testability, and simplifies code maintenance.

Benefits:

  • Improves modularity
  • Enables easier unit testing (via mock dependencies)
  • Promotes adherence to SOLID principles (especially the Dependency Inversion

Principle)

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Review the concept and prepare a concise verbal explanation with a real project example.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

.NET Core has a built-in DI container that's tightly integrated into the framework. When

you create a new ASP.NET Core project, DI is configured automatically and used in

controllers, middleware, services, etc. You register dependencies in the Program.cs or

Startup.cs file using IServiceCollection.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Services are registered in the Program.cs or Startup.cs file using the

IServiceCollection interface. Example:

builder.Services.AddTransient<IProductService, ProductService>();

builder.Services.AddScoped<IOrderService, OrderService>();

builder.Services.AddSingleton<ILoggingService, LoggingService>();

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Transient: A new instance is created every time it is requested.
  • Scoped: A single instance is created per request/HTTP request.
  • Singleton: A single instance is created and shared across the application lifetime.

Lifetime Created Per Use Case

Transient Every injection Lightweight, stateless services

Scoped HTTP Request Web services handling per-request

data

Singleton App lifetime Logging, configuration, cache

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Circular dependencies occur when two or more services depend on each other, creating an

infinite loop. To handle them:

  • Refactor the code to remove tight coupling.
  • Use interfaces or events to break the cycle.
  • Consider using property injection carefully (not recommended as a first choice).
  • Rethink your design – circular dependencies often indicate architectural issues.
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Easier mocking of dependencies using frameworks like Moq or NSubstitute.
  • No need to instantiate real implementations (e.g., database access) for tests.
  • Improved isolation of the unit under test.
  • Faster, more reliable tests due to lack of external dependency reliance.
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Yes, DI can be implemented manually without using a DI container. You simply pass

dependencies through constructors or methods:

public class OrderService

private readonly IOrderRepository _repo;

public OrderService(IOrderRepository repo)

_repo = repo;

// Manual injection

var repo = new OrderRepository();

var service = new OrderService(repo);

This is suitable for small or simple applications, though not scalable for large apps.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Over-injection (too many dependencies in one class – violates SRP)
  • Service locator anti-pattern
  • Incorrect lifetimes, leading to memory leaks or unintended reuse
  • Tight coupling to the DI container (e.g., using container APIs in business logic)
  • Circular dependencies due to poor design
  • Registering services in the wrong order or not at all
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Inversion of Control (IoC) is a broader principle where control over object creation and

dependency resolution is transferred from the class itself to an external framework or

container.

Dependency Injection is a specific implementation of IoC, where the dependencies are

injected into a class rather than the class creating them internally. So, DI is one way to

achieve IoC.

Single Responsibility Principle

(SRP)

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Single Responsibility Principle (SRP) states that a class should have only one

reason to change. In other words, it should have only one responsibility or job.

Each class should do one thing, and do it well.

For example, a class that handles user authentication should not also be responsible for

logging or sending emails.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

You can identify SRP violations by asking questions like:

  • Does this class perform more than one function (e.g., data access and business

logic)?

  • Does it change for different reasons (e.g., changes in UI and database)?
  • Does it have too many dependencies or too much code?
  • Are there “and”s in the class name or method descriptions? E.g.,

ReportGeneratorAndPrinter.

Common signs:

  • Long classes or large files
  • Many unrelated methods
  • Hard-to-test code
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Before (SRP Violation):

public class Invoice

public void GenerateInvoice() { /* logic */ }

public void SaveToDatabase() { /* logic */ }

public void SendEmail() { /* logic */ }

This class has 3 responsibilities: generating, saving, and emailing.

After (SRP-compliant):

public class InvoiceGenerator

public void Generate() { /* logic */ }

public class InvoiceRepository

public void Save(Invoice invoice) { /* logic */ }

public class EmailService

public void Send(Invoice invoice) { /* logic */ }

Now each class has a single reason to change.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

SRP improves maintainability by:

  • Reducing complexity – Classes are smaller and easier to understand.
  • Easier testing – Each class can be tested in isolation.
  • Better separation of concerns – Business logic, data access, and infrastructure

code are kept apart.

  • Lower risk of bugs – Changes in one responsibility don’t affect others.

Ultimately, it leads to more modular, flexible, and robust code.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

If a class has multiple responsibilities:

  • It becomes tightly coupled and harder to change without affecting other parts.
  • Changes are more error-prone and often introduce bugs.
  • Testing becomes harder since the class relies on multiple behaviors.
  • Code reusability and readability suffer due to mixed concerns.
  • You violate SRP, which makes code harder to maintain in the long run.

Open/Closed Principle (OCP)

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Open/Closed Principle (OCP) states that:

Software entities (classes, modules, functions) should be open for

extension but closed for modification.

This means you should be able to add new behavior to a class without changing its

existing code, which helps avoid breaking existing functionality.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

To design classes that follow OCP:

  • Use abstraction (interfaces or abstract classes).
  • Rely on polymorphism and inheritance.
  • Apply composition over inheritance when suitable.
  • Follow design principles like Strategy, Decorator, or Template Method patterns.

✅ Extend behavior through new classes rather than modifying existing code.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Several design patterns are built around the idea of making systems extensible without

modifying core logic:

Pattern How It Helps With OCP

Strategy Allows changing behavior by swapping strategies.

Decorator Adds new responsibilities dynamically without changing original code.

Template Method Allows subclasses to override certain steps in an algorithm.

Factory Method Makes it easy to introduce new types without altering existing logic.

Observer Extends behavior in reaction to events without altering the source.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Before (OCP Violation):

public class DiscountCalculator

public decimal CalculateDiscount(string customerType)

if (customerType == "Regular") return 10;

if (customerType == "Premium") return 20;

if (customerType == "VIP") return 30;

return 0;

If you need to support a new customer type, you must modify this method — violating OCP.

After (OCP Compliant):

public interface IDiscountStrategy

decimal GetDiscount();

public class RegularCustomerDiscount : IDiscountStrategy

public decimal GetDiscount() => 10;

public class PremiumCustomerDiscount : IDiscountStrategy

public decimal GetDiscount() => 20;

public class VipCustomerDiscount : IDiscountStrategy

public decimal GetDiscount() => 30;

Now you can add new customer types without modifying existing code — just create a new

strategy.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Interfaces and abstract classes provide a contract that other classes can

implement or inherit.

  • They enable polymorphism, which allows behavior to be extended without altering

existing code.

  • By programming to abstractions (not concrete implementations), you can easily

introduce new behavior (via new implementations) while keeping the core logic

unchanged.

✅ OCP encourages extending via new subclasses or interface implementations, not

modifying existing ones.

Liskov Substitution Principle (LSP)

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Liskov Substitution Principle (LSP) states that:

Subtypes must be substitutable for their base types without altering the

correctness of the program.

In other words, if class S is a subclass of class T, then objects of type T should be

replaceable with objects of type S without breaking the application.

This ensures that inheritance models is-a relationships correctly.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Violating LSP can lead to:

  • Unexpected behavior when a subclass does not honor the contract of the base

class.

  • Code that breaks at runtime when substituting a derived class.
  • Tightly coupled code that depends on specific implementations rather than

abstractions.

  • Unit tests failing when testing subclasses in place of base classes.

Essentially, it defeats the purpose of polymorphism.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Example (Violation of LSP):

public class Rectangle

public virtual int Width { get; set; }

public virtual int Height { get; set; }

public int Area() => Width * Height;

public class Square : Rectangle

public override int Width

set { base.Width = base.Height = value; }

public override int Height

set { base.Width = base.Height = value; }

Now if you substitute Rectangle with Square:

Rectangle rect = new Square();

rect.Width = 5;

rect.Height = 10;

Console.WriteLine(rect.Area()); // Outputs 100, but logically

expected 50

❌ The behavior is incorrect — this is a violation of LSP.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

To ensure subclasses follow LSP:

  • Subclasses should not override behavior in a way that breaks expected behavior.
  • Subclasses should preserve the invariants and preconditions/postconditions of the

base class.

  • Avoid overriding methods to throw exceptions for valid base class behavior.
  • Use composition over inheritance if a subclass doesn’t strictly conform to the base

class behavior.

  • Write unit tests to verify that the subclass behaves identically to the base class in all

valid scenarios.

✅ Ask yourself: Can this subclass be used anywhere the base class is used — without

surprises?

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

LSP is fundamentally about correct use of inheritance. While inheritance allows code

reuse, LSP ensures that the behavior of subclasses remains consistent with that of the

base class.

If a subclass changes the meaning or violates the expectations of the base class’s

behavior, it's misusing inheritance.

Interface Segregation Principle (ISP)

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Interface Segregation Principle (ISP) states that:

Clients should not be forced to depend on interfaces they do not use.

This means that interfaces should be small and focused, containing only the methods that

are relevant to the implementing class. It prevents "fat" or "bloated" interfaces.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Small, specific interfaces:

  • Promote separation of concerns
  • Make classes easier to implement and test
  • Reduce the risk of breaking changes
  • Avoid forcing classes to implement irrelevant methods
  • Increase reusability and readability

In contrast, large interfaces force classes to implement methods they may not need —

leading to fragile and cluttered code.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

ISP improves code flexibility by:

  • Allowing classes to only depend on what they actually use
  • Making it easier to extend or replace functionality without affecting unrelated parts
  • Enabling composition over inheritance
  • Making interfaces easier to mock or stub in unit tests
  • Encouraging clean, modular design

Smaller interfaces result in lower coupling and better maintainability.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Violation Example:

public interface IWorker

void Work();

void Eat();

void Sleep();

public class Robot : IWorker

public void Work() { /* logic */ }

public void Eat() { throw new NotImplementedException(); }

public void Sleep() { throw new NotImplementedException(); }

❌ Robot is forced to implement Eat() and Sleep(), which don’t make sense for it.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Refactored Using ISP:

public interface IWorkable

void Work();

public interface IFeedable

void Eat();

public interface ISleepable

void Sleep();

public class Human : IWorkable, IFeedable, ISleepable

public void Work() { }

public void Eat() { }

public void Sleep() { }

public class Robot : IWorkable

public void Work() { }

✅ Now each class implements only the interfaces it needs — in line with ISP.

Inversion Principle (DIP)

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Dependency Inversion Principle (DIP) states that:

High-level modules should not depend on low-level modules. Both should

depend on abstractions.

Abstractions should not depend on details. Details should depend on

abstractions.

In other words:

  • High-level business logic shouldn't depend on concrete implementations.
  • Instead, both high- and low-level components should depend on interfaces or

abstract classes.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Aspect Dependency Inversion Principle (DIP) Dependency Injection (DI)

Definitio

A design principle about depending on

abstractions

A technique for passing

dependencies

Goal Decouple high-level logic from low-level

details

Provide dependencies to

objects

Relation DIP motivates the need for DI DI is a way to implement DIP

Focus What to depend on (abstractions) How dependencies are supplied

✅ DIP is a design principle, while DI is a design pattern/technique to implement that

principle.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Abstractions (e.g., interfaces or abstract classes):

  • Decouple components so changes in one don’t ripple through others
  • Enable substitution of different implementations easily
  • Allow for easier unit testing with mocks/stubs
  • Promote extensibility and maintainability
  • Serve as contracts that both high- and low-level modules depend on
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

❌ Without DIP (Tightly Coupled):

public class FileLogger

public void Log(string message) => Console.WriteLine("File log:

" + message);

public class OrderService

private readonly FileLogger _logger = new FileLogger();

public void ProcessOrder()

// Logic

_logger.Log("Order processed.");

  • OrderService is tightly coupled to FileLogger.

✅ With DIP (Loosely Coupled via Abstraction):

public interface ILogger

void Log(string message);

public class FileLogger : ILogger

public void Log(string message) => Console.WriteLine("File log:

" + message);

public class OrderService

private readonly ILogger _logger;

public OrderService(ILogger logger)

_logger = logger;

public void ProcessOrder()

// Logic

_logger.Log("Order processed.");

Now OrderService depends on the abstraction (ILogger), not the concrete

FileLogger. You can easily substitute with DatabaseLogger, ConsoleLogger, or a

mock in tests.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

✅ Key Benefits:

  • Decouples components — changes in low-level modules won’t affect high-level

ones

  • Improves testability — you can easily inject mocks/stubs
  • Enhances flexibility — swap implementations without touching core logic
  • Promotes reuse — abstractions can be used across different modules
  • Supports SOLID architecture — especially when combined with DI and IoC

containers

Advanced & Scenario-Based

Questions

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Design patterns provide structured, reusable solutions that embody SOLID principles. For

example, the Strategy pattern supports OCP by allowing behavior extension without

modifying existing code; Repository separates data access (SRP); Dependency Injection

supports DIP by decoupling high- and low-level modules. Using patterns helps keep code

clean, modular, and maintainable.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Unit of Work coordinates multiple Repositories and commits changes in a single

transaction. For example:

public interface IUnitOfWork : IDisposable

IProductRepository Products { get; }

IOrderRepository Orders { get; }

int Complete();

public class UnitOfWork : IUnitOfWork

private readonly DbContext _context;

public IProductRepository Products { get; }

public IOrderRepository Orders { get; }

public UnitOfWork(DbContext context)

_context = context;

Products = new ProductRepository(_context);

Orders = new OrderRepository(_context);

public int Complete() => _context.SaveChanges();

public void Dispose() => _context.Dispose();

This ensures atomic commits across repositories.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Testing singletons/statics is tricky due to global state. Best practices include:

  • Refactor to use interfaces and DI instead of static/singletons.
  • Wrap static calls behind interfaces so you can mock them.
  • Use specialized mocking tools (e.g., Microsoft Fakes) if refactoring isn't possible.
  • Avoid static state to improve testability.
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Mediator Pattern centralizes communication between components, preventing direct

dependencies and reducing complexity. It promotes loose coupling and simplifies

interactions. Alternatively, the Observer Pattern enables event-driven decoupling, and

Facade Pattern provides a simplified interface to complex subsystems.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Define a common interface, e.g., IPaymentStrategy with a method Pay(). Implement

concrete strategies for each payment method (CreditCard, PayPal, etc.). Use a context class

to invoke the selected strategy at runtime, enabling easy extension without modifying

existing code.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

DAO (Data Access Object) focuses on low-level database operations and CRUD, typically

mapping tables to objects.

Repository abstracts data access at the domain level, working with aggregates/entities and

encapsulating business logic. Repository often uses DAO internally but is more aligned with

domain-driven design.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Identify classes violating SRP and break them down.
  • Introduce abstractions and interfaces to decouple components (DIP).
  • Replace conditional logic with polymorphism to respect OCP.
  • Split large interfaces (ISP).
  • Check inheritance hierarchies to maintain LSP.
  • Inject dependencies instead of direct instantiation.
  • Incrementally refactor with unit tests to ensure behavior remains consistent.
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Use AOP (Aspect-Oriented Programming) techniques or design patterns like Decorator

to separate cross-cutting concerns from business logic. In .NET, middleware, filters, or

interceptors can manage concerns like logging or authorization, keeping SRP intact.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

DI containers use reflection to inspect constructors of requested services, resolve

dependencies recursively from their registrations, apply lifecycle scopes (Singleton, Scoped,

Transient), and build the full object graph to return fully constructed instances.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Define plugin contracts with interfaces (DIP).
  • Load plugins dynamically using reflection or MEF.
  • Use DI to inject dependencies into plugins.
  • Ensure plugins follow SRP with focused responsibilities.
  • Use Factory or Strategy patterns to instantiate plugins.
  • Keep core system closed for modification but open for extension (OCP).
  • Separate cross-cutting concerns externally.

Practical .NET Questions

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

ASP.NET Core MVC has built-in support for Dependency Injection.

  • Register services in Startup.cs within ConfigureServices method using

IServiceCollection:

public void ConfigureServices(IServiceCollection services)

services.AddControllersWithViews();

services.AddScoped<IProductService, ProductService>(); //

Example

  • Inject dependencies via constructor injection in controllers or services:

public class HomeController : Controller

private readonly IProductService _productService;

public HomeController(IProductService productService)

_productService = productService;

public IActionResult Index()

var products = _productService.GetAll();

return View(products);

The framework resolves and injects dependencies automatically.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • IServiceCollection: A container used during app startup to register services and

their lifetimes (Scoped, Transient, Singleton). It acts as a service registry.

  • IServiceProvider: The built container that resolves and provides instances of

registered services at runtime. It uses the registrations to create and inject

dependencies.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Register DbContext with DI in Startup.cs:

services.AddDbContext<AppDbContext>(options =>

options.UseSqlServer(Configuration.GetConnectionString("DefaultConne

ction")));

  • Implement Repositories for entities injecting AppDbContext.
  • Implement Unit of Work which holds multiple repositories and calls SaveChanges()

on the DbContext:

public interface IUnitOfWork : IDisposable

IProductRepository Products { get; }

int Complete();

public class UnitOfWork : IUnitOfWork

private readonly AppDbContext _context;

public IProductRepository Products { get; private set; }

public UnitOfWork(AppDbContext context)

_context = context;

Products = new ProductRepository(_context);

public int Complete() => _context.SaveChanges();

public void Dispose() => _context.Dispose();

Register UnitOfWork in DI container as Scoped.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Use mocking libraries like Moq, NSubstitute, or FakeItEasy.
  • Create mocks of interfaces and inject them into the class under test:

var mockRepo = new Mock<IProductRepository>();

mockRepo.Setup(repo => repo.GetAll()).Returns(new List<Product> {

... });

var service = new ProductService(mockRepo.Object);

// Act & Assert

  • This allows testing in isolation without hitting real databases or external services.
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Chain of Responsibility: Middleware components form a pipeline where each

decides to pass control or handle the request.

  • Decorator: Middleware wraps around the next component, adding behavior before

or after.

  • Factory: Middleware components can be created via factories for configurable

pipeline setup.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Define a caching interface:

public interface ICacheStrategy

void Cache(string key, object value);

object Retrieve(string key);

  • Implement strategies like MemoryCacheStrategy,

DistributedCacheStrategy.

  • Use DI or factory to inject the chosen strategy at runtime:

public class CacheContext

private readonly ICacheStrategy _cacheStrategy;

public CacheContext(ICacheStrategy cacheStrategy)

_cacheStrategy = cacheStrategy;

public void Cache(string key, object value) =>

_cacheStrategy.Cache(key, value);

This enables switching caching mechanisms without code changes.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Abstract Factory: Provides an interface for creating families of related objects

without specifying concrete classes.

Example: Creating UI components for different OS (Windows, Mac).

  • Builder: Focuses on step-by-step construction of a complex object, allowing different

representations.

Example: Building a complex House with various parts (walls, doors, roof).

Summary: Abstract Factory is about families of products, Builder is about complex

construction process.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Apply Single Responsibility Principle (SRP) by splitting responsibilities into smaller

classes.

  • Use composition instead of inheritance to delegate behavior.
  • Extract business logic into services or helpers.
  • Introduce abstractions to isolate concerns.
  • Continuously refactor large classes and add unit tests.
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Resharper: Provides code analysis and refactoring hints.
  • SonarQube / SonarCloud: Analyzes code quality and reports SOLID violations.
  • FxCop / Roslyn analyzers: Provide static analysis with custom rules.
  • NDepend: Deep architecture and dependency analysis tool.
  • StyleCop: Enforces coding style which indirectly helps maintain SOLID code.
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Mediator decouples components by centralizing communication, supporting SRP and

DIP by reducing direct dependencies.

  • It fits DI because the mediator itself can be injected where needed.
  • It supports OCP by allowing new communication routes or handlers without

modifying existing components.

  • Helps avoid tight coupling in complex workflows or CQRS patterns.

Behavioral / Conceptual Questions

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

In a recent project, we had a monolithic service class handling multiple responsibilities,

making it hard to maintain and extend. By applying Single Responsibility Principle (SRP),

we split the class into focused services, each with a clear purpose. This drastically improved

readability, reduced bugs, and made it easier to add new features without risking

regressions. The project became more testable because each small class could be unit

tested independently.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Yes. In one project, a singleton was used without thread safety, causing race conditions

when accessed concurrently. This led to inconsistent state and application crashes. We

resolved it by implementing thread-safe lazy initialization using Lazy<T> in .NET, ensuring

the singleton instance was created safely once, even under heavy parallel access.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

I prioritize YAGNI (You Aren’t Gonna Need It) to avoid over-engineering. SOLID principles

guide design for flexibility and maintainability, but I apply them pragmatically: start with

simple solutions and refactor as requirements evolve. Writing tests early helps identify pain

points justifying additional abstractions. Communication with the team ensures we don’t add

complexity prematurely but keep the codebase adaptable.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Challenges include:

  • Legacy code with tight coupling, making decomposition hard.
  • Risk of introducing bugs while splitting responsibilities or introducing abstractions.
  • Managing dependencies and lifetimes correctly when injecting dependencies.
  • Convincing stakeholders that refactoring time is valuable.
  • Balancing between adhering strictly to SOLID vs. keeping code understandable and

performant.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

I use a combination of:

  • Simple examples showing before/after code refactoring.
  • Pair programming sessions to explain thought processes.
  • Encouraging reading and discussing classic books like “Clean Code” and “Design

Patterns”.

  • Practical coding exercises and code reviews focused on SOLID principles.
  • Showing real project scenarios where principles improved code quality and

maintainability.

  • Promoting a culture of continuous learning and curiosity.

Bonus / Miscellaneous

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Inheritance creates an “is-a” relationship, where a subclass inherits behavior and

properties from a parent class. It can lead to tight coupling and fragile hierarchies if

overused.

  • Composition creates a “has-a” relationship, where a class contains instances of

other classes and delegates behavior to them. It’s more flexible and promotes loose

coupling.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Decorator adds additional responsibilities to objects dynamically without altering

their interface. It wraps the original object to extend behavior.

  • Proxy controls access to an object, possibly adding lazy initialization, access control,

or logging, without changing its interface.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Adapter converts the interface of a class into another interface clients expect, allowing

incompatible interfaces to work together. It promotes Open/Closed Principle (OCP) by

enabling new integrations without modifying existing code.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Use the Proxy or Virtual Proxy pattern where a placeholder object controls access to the

real object and defers its creation until needed. In .NET, Lazy<T> provides built-in lazy

loading.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Service Locator anti-pattern: Hides dependencies instead of injecting them

explicitly.

  • Overusing Singleton: Leads to hidden global state and testing difficulties.
  • Improper Singleton thread safety: Causes race conditions.
  • Injecting concrete implementations: Violates DIP.
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Template Method defines the skeleton of an algorithm in a base class, deferring some steps

to subclasses. It allows subclasses to redefine parts of the algorithm without changing its

structure. It supports OCP by enabling extensions through inheritance.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

SOLID promotes small, single-responsibility services (SRP), clear interfaces (ISP), loose

coupling (DIP), and extendable design (OCP). This aligns well with microservices by

encouraging modular, maintainable, and testable service boundaries.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

The Command Pattern encapsulates requests as objects, allowing operations to be stored,

undone, or redone by maintaining command history.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Use interfaces and abstractions (DIP).
  • Apply Dependency Injection.
  • Modularize code into bounded contexts or separate projects.
  • Use events or messaging for decoupled communication.
  • Avoid static state and global variables.
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Encapsulates a request as an object with methods to execute and possibly undo the

operation. The invoker calls commands without knowing the action details, supporting

decoupling and flexible request handling.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Cohesion: Degree to which elements of a module belong together. High cohesion

means focused, well-defined responsibilities.

  • Coupling: Degree of interdependence between modules. Low coupling means

modules are independent and changes in one don’t affect others.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Use API contracts and versioning.
  • Employ service discovery and load balancing.
  • Prefer asynchronous messaging/event-driven architecture to reduce tight

coupling.

  • Apply circuit breakers and retries for fault tolerance.
Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

  • Interfaces define contracts with no implementation, supporting ISP and DIP by

allowing flexible implementations.

  • Abstract classes provide a base implementation and shared code, useful for

Template Method pattern and partial abstraction.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Builder separates complex object construction from its representation. For example, building

an HttpRequest with optional headers, query params, and body:

public class HttpRequestBuilder

private HttpRequestMessage _request = new HttpRequestMessage();

public HttpRequestBuilder SetMethod(HttpMethod method)

_request.Method = method;

return this;

public HttpRequestBuilder AddHeader(string key, string value)

_request.Headers.Add(key, value);

return this;

public HttpRequestMessage Build() => _request;

Allows building requests step-by-step fluently.

Permalink

Design Patterns & SOLID Design Patterns in C# · SOLID

Observer supports SRP by separating notification logic from core business logic and DIP by

depending on abstractions (observers). It fits DI because observers can be injected, allowing

flexible runtime subscriptions and loose coupling.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • For more complex grammars, the interpreter may become inefficient.

Optimizations such as memoization (caching results) can be used to avoid

redundant evaluations, particularly for recursive expressions.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The ISortStrategy interface defines a common method (Sort) that all concrete

strategies must implement. This allows clients (in this case, the Sorter class) to

work with any strategy that implements this interface.

public interface ISortStrategy

void Sort(List<int> list);

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The IIterator<T> interface defines the contract for all iterators. It ensures

that all iterators implement the basic functionality of checking for the next

element (HasNext()) and returning the next element (Next()).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Pizza class is the Product that we are constructing. It has properties for

Dough, Sauce, and a list of Toppings. The ToString() method is

overridden to provide a string representation of the pizza.

public class Pizza

public string Dough { get; set; }

public string Sauce { get; set; }

public List<string> Toppings { get; } = new List<string>();

public override string ToString() =>

$"Pizza with {Dough} dough, {Sauce} sauce and toppings:

{string.Join(", ", Toppings)}";

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • If the object’s state is large or changes frequently, the Memento Pattern can

result in significant memory usage, as you need to store many copies of the

state (each memento).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Iterator Pattern can be extended to support reverse iteration or provide

additional functionality like removing items during iteration.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The mediator manages communication between the users. It maintains a list

of all users and broadcasts messages to all other users when one user sends

a message.

  • This keeps the users from directly knowing about each other, thus promoting

loose coupling.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Logger class is the handler interface that defines the contract for

handling log messages. It includes a reference to the next logger in the chain

(NextLogger) and a method (LogMessage) to process a message. If the

current handler cannot handle the message, it passes the request along to

the next handler in the chain.

public abstract class Logger

protected Logger NextLogger;

public void SetNext(Logger nextLogger) => NextLogger =

nextLogger;

public void LogMessage(string message, LogLevel level)

if (CanHandle(level))

Handle(message);

else

NextLogger?.LogMessage(message, level);

protected abstract bool CanHandle(LogLevel level);

protected abstract void Handle(string message);

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The NewsPublisher class acts as the subject in the Observer Pattern. It

maintains a list of IObserver instances (subscribers) and provides methods

to add (Subscribe), remove (Unsubscribe), and notify them (Notify).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Chain of Responsibility allows handlers to be decoupled from the client

code. The client doesn’t need to know which handler will process the request,

only that the request will eventually be processed by some handler in the

chain.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Observer Pattern promotes loose coupling between the subject and the

observers. The subject does not know about the specific observers, only that

they implement the IObserver interface. This makes the system more

Follow:

flexible and easier to maintain.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In the Program class, we set up a chain of responsibility by calling

SetNext() on the infoLogger and passing it the errorLogger. This

ensures that the InfoLogger will process log messages with the Info level,

while the ErrorLogger will handle Error level messages.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The client interacts with the proxy (ProxyImage), which implements the

same interface (IImage) as the real subject (RealImage).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Since the mediator handles all interactions between objects, it becomes a

critical part of the system. If the mediator fails, the entire communication

system breaks down. This could be mitigated by introducing fault tolerance or

redundancy in the mediator.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The TextMemento class holds the state of the TextEditor object. It only exposes

the state (the text content) and doesn’t allow direct manipulation of that state.

  • The Memento is a snapshot of the internal state of the TextEditor.

public class TextMemento

public string Text { get; }

public TextMemento(string text) => Text = text;

Follow:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The command (in this case, AddTextCommand) encapsulates the request to

add text to the document as an object. This allows for parameterization of the

command with different requests (e.g., adding different text) while decoupling

the sender (the TextEditor) from the receiver (Document).

Follow:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • A virtual proxy can be used to load large images or videos on-demand,

especially when dealing with high-resolution media files that could be costly to

load upfront.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

perform operations on them that vary.

  • For example, in cases where you have a set of classes that are part of a

complex hierarchy (like a shopping cart with various types of products), and

you need to add new behaviors without changing the objects themselves.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The sender (the TextEditor) is decoupled from the receiver (Document).

The TextEditor only knows how to invoke commands but does not need to

understand the details of the operations (e.g., how the text is added or

removed).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • You can extend the system by adding redo functionality. After an undo

operation, you could store the undone command in a separate stack and

allow users to redo the previous undo operation.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Iterator Pattern is commonly used when working with product lists,

customer lists, or any other collection where you need to iterate over items

sequentially. For instance, in an e-commerce application, you might use an

iterator to list products, iterate through available categories, or paginate

results.

Follow:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • This is the base interface that defines a common method ShowInfo() that

will be implemented by both leaf and composite components.

public interface IFileSystemComponent

void ShowInfo();

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The pattern separates the algorithm (e.g., calculating total with discounts)

from the objects on which it operates. This makes the object structure

(elements) cleaner, as they are not responsible for the business logic.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The IShoppingCartVisitor interface defines the operations that can be

performed on the IShoppingCartElement objects. In this case, the visitor defines

Visit(Book book) and Visit(Fruit fruit) methods for different product

types.

public interface IShoppingCartVisitor

void Visit(Book book);

void Visit(Fruit fruit);

Follow:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The IChatMediator interface defines two key operations:

■ SendMessage(string message, User user): Sends a

message from a user to all other registered users.

■ RegisterUser(User user): Registers users with the mediator so

they can send and receive messages.

public interface IChatMediator

void SendMessage(string message, User user);

void RegisterUser(User user);

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • A classic example of the Mediator Pattern is a chat application, where the

mediator is responsible for sending messages between users. It ensures that

messages are routed correctly without the users needing to know about each

other.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Both File and Directory implement the IFileSystemComponent

interface, which defines the common method ShowInfo(). This allows us to

treat both files and directories uniformly.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Both files and directories are treated the same, as they implement the

IFileSystemComponent interface. This makes it easier to manage a mixed

structure of individual and composite objects.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Memento Pattern preserves encapsulation because the state is stored

in the Memento object, and the TextEditor is not exposed to direct

manipulation of its internal state. The only way to change or access the state

is through well-defined methods (Save and Restore).

Follow:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The most common application of the Composite Pattern is in representing

file systems. A file system is inherently hierarchical: directories contain files

and subdirectories, and those subdirectories can contain further files or

subdirectories. The Composite Pattern allows for easy traversal and

management of this hierarchical structure.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

Follow:

  • This is the common interface that both the real object (RealImage) and the proxy

object (ProxyImage) implement. It defines the method Display() that both

concrete classes must implement.

public interface IImage

void Display();

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Directory class currently only has an Add() method for adding

components. It could be improved by adding a Remove() method to allow for

the dynamic removal of files or subdirectories.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • When you have a series of steps that must be followed in a specific order, but

some of the steps need to be customized for different situations. For example,

when creating frameworks for processes like data parsing, game initialization,

or file handling.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • This is the base interface that defines the common methods for the Cost()

and Description() that every coffee component will implement.

public interface ICoffee

double Cost();

string Description();

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • ICoffee defines the basic methods that any coffee type must implement.

This allows the decorators to work with any class that implements this

interface, providing flexibility to decorate any coffee object.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The strategy pattern allows algorithms to be swapped at runtime, making the

code more flexible. You can add new sorting algorithms without changing the

context class, thus adhering to the Open/Closed Principle (open for

extension, closed for modification).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The ITrafficLightState interface defines a method (Change) that allows

the traffic light to transition between states (Red, Green, Yellow).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The TextEditor is the originator of the state. It holds the text that changes

over time and can save and restore its state using mementos.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Decorator Pattern is ideal for situations like coffee shops, where

customers can customize their coffee with various add-ons (milk, sugar,

whipped cream, flavor syrups, etc.). Each add-on is a decorator that adds a

cost and modifies the description of the order without modifying the core

coffee object.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The pattern enforces a rigid structure for the algorithm, meaning that

subclasses cannot change the overall order or flow of steps. If you need to

adjust the structure of the algorithm, it may require changes to the base class.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The common structure of the algorithm is defined in the abstract class, so

subclasses don't have to repeat the same steps. Only the details of specific

steps need to be implemented in each subclass.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • You could introduce more decorators, such as WhippedCreamDecorator,

ChocolateDecorator, or CaramelDecorator, for a richer coffee

experience.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Cloning objects is often more efficient than creating new ones from scratch,

especially when the object is complex or expensive to create. This can be

particularly useful in performance-sensitive applications like games or

simulations.

Follow:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

Follow:

  • These classes encapsulate the complex functionality of the system. For

instance, turning the amplifier on or off, or playing a movie in the DVD player.

These actions are usually cumbersome for the user to manage directly.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Use the Strategy Pattern when you have multiple algorithms for a specific

task and want to switch between them easily (e.g., sorting, encryption,

compression).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The ISortStrategy interface allows any concrete sorting algorithm to be

swapped in and out. The context (Sorter) doesn't need to know the specifics

of the algorithm; it only knows that it can call the Sort method on any

strategy that implements this interface.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • By providing a unified interface, the Facade Pattern simplifies the interaction

with complex subsystems. The user only needs to interact with a few

high-level methods, making the system easier to use.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • It can increase the number of classes in the system. If the number of

algorithms is small, using the Strategy Pattern might be over-engineering.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Recipe class defines the template method Cook, which contains the algorithm's

skeleton. It delegates the implementation of specific steps (GatherIngredients,

Prepare, and CookMethod) to subclasses by making them abstract. The Serve

method is concrete and always executes the same way for all recipes.

public abstract class Recipe

public void Cook()

Follow:

GatherIngredients();

Prepare();

CookMethod();

Serve();

protected abstract void GatherIngredients();

protected abstract void Prepare();

protected abstract void CookMethod();

private void Serve() => Console.WriteLine("Serving the dish.");

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In real-life home theaters, turning on multiple devices like an amplifier, DVD

player, and projector can be tedious. A Facade Pattern can simplify this into

a single button or command (like WatchMovie()), where the user only

needs to press one button to turn everything on.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The elements in the object structure (Book, Fruit) implement the Accept

method, which is designed to accept a visitor. This method typically calls the

appropriate visit method (Visit(Book book) or Visit(Fruit fruit))

on the visitor.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • If the home theater system grows, you can easily add more components (e.g.,

projector, lights, sound system) to the facade without modifying the client

code. This extends the flexibility of the facade as the system becomes more

Follow:

complex.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • This interface defines the common method Log that will be implemented by

all types of loggers (e.g., file, console).

public interface ILogger

void Log(string message);

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The ICommand interface defines two methods:

■ Execute(): Executes the command.

■ Undo(): Reverts the command if the user wishes to undo the action.

Follow:

public interface ICommand

void Execute();

void Undo();

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The LoggerFactory class defines a factory method CreateLogger that

returns an ILogger object. This is a generic interface for creating various

Follow:

logger types without specifying the concrete class directly.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • When you have an object that can be in multiple predefined states and its

behavior depends on the current state (e.g., traffic lights, order processing

systems).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The IExpression interface defines the contract for all expressions in the

grammar, allowing them to be interpreted (evaluated). Every class that

implements this interface will provide its own interpretation logic.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The IUIFactory interface defines methods for creating abstract product

types like buttons and checkboxes. This ensures that every concrete factory

will implement the same methods, but each will provide platform-specific

products.

public interface IUIFactory

IButton CreateButton();

ICheckbox CreateCheckbox();

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • As mentioned, logging systems often use the Factory Method to allow

different log outputs. For example, a logging framework can provide loggers

that write to the console, files, databases, or cloud services, with the user

choosing the appropriate logger type via a factory.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The State Pattern introduces a separate class for each state, which can lead

to an increase in the number of classes in the system. For systems with many

states, this can cause complexity.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • This interface defines the Clone() method that will be used to create a copy

of an object. Any class that needs to be cloned must implement this interface.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In a more advanced system, you could dynamically choose which factory to

use based on external configurations, like settings or environment variables.

This would enable the system to switch between different logging

mechanisms or database connections without recompiling the application.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Used to delay the creation or initialization of an expensive object until it is

actually needed, like the ProxyImage example above.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The ITrafficLightState interface defines a method (Change) that allows the

state to transition to another state. The method accepts a TrafficLight object as

a parameter to facilitate the state change.

public interface ITrafficLightState

void Change(TrafficLight light);

  • Each concrete state class (Red, Green, Yellow) will implement this interface, defining

the specific behavior of the traffic light for that state.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • This class represents the Flyweight object. It contains the intrinsic state that

is shared across multiple instances (the character symbol, in this case), and it

provides a Display method to show the character's symbol at a particular

coordinate.

public class Character

private readonly char _symbol;

public Character(char symbol) => _symbol = symbol;

public void Display(int x, int y) =>

Console.WriteLine($"Character: {_symbol} at ({x}, {y})");

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • A news website where multiple users subscribe to receive notifications when

new articles or breaking news are published.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Character class holds the intrinsic state (the character symbol), which

is shared across all instances. This makes it an ideal candidate for the

Flyweight Pattern because multiple characters (e.g., 'H', 'e', 'l') may appear

many times in the same text, but they only need one Character object for

the symbol.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The singleton instance is created when the class is loaded, guaranteeing

thread safety without locking. However, it may have a slight performance

overhead due to the instance being created regardless of whether it is

needed.

public class Singleton

private static readonly Singleton _instance = new Singleton();

private Singleton() { }

public static Singleton Instance => _instance;

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • By sharing common intrinsic states (like the symbol in this case), the

Flyweight Pattern reduces memory consumption significantly. Instead of

creating multiple objects for each appearance of a character, only one object

is created for each unique character.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Many games display large amounts of text (e.g., in dialogues, menus, or

scores). Using the Flyweight Pattern, you can optimize memory usage by

reusing the same Character objects for common letters or symbols, rather

than creating a new object for each instance.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Bridge pattern allows you to modify the abstraction (shapes) and the

implementation (drawing API) independently, providing a cleaner and more

modular design.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • While adding new operations is easy, adding new element types can be

challenging. Every new element requires modifying all existing visitor classes

to implement the new Visit method.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Singleton can act as a global variable, which may make it harder to track

state changes and can lead to issues with dependencies.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The ITarget interface defines the expected interface that the client will use.

It has a method Request() that the client expects to call.

public interface ITarget

void Request();

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • If the number of unique characters or objects grows significantly, the

CharacterFactory can implement cache management strategies like

LRU (Least Recently Used) or FIFO (First In, First Out) to evict older or

unused objects and maintain memory efficiency.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Singleton Pattern ensures that a class has only one instance, and it

provides a global access point to that instance. This is especially useful when

managing resources that should be shared across the application, such as

configuration settings, logging, or database connections.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • This interface defines methods for subscribing, unsubscribing, and notifying

observers. The subject manages a list of observers and notifies them when there is

an update.

public interface INewsPublisher

Follow:

void Subscribe(IObserver observer);

void Unsubscribe(IObserver observer);

void Notify(string news);

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Adapter pattern allows you to integrate existing systems or third-party

libraries without modifying their code. It enables compatibility between

incompatible interfaces.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • When there is a need to store and share global configuration settings across

the application (e.g., database connection strings, file paths, API keys).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In a text editor (such as Microsoft Word or Notepad), users can press Ctrl + Z

to undo the most recent changes. Each time the user types, the editor saves

a snapshot of the text as a Memento. Pressing Ctrl + Z restores the text to its

previous state.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

Review the concept and prepare a concise verbal explanation with a real project example.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The ConfigurationManager class is designed to ensure that there is only one

instance of it throughout the application.

  • The Instance property handles the lazy initialization of the singleton instance,

ensuring that it's only created once and then reused.

public class ConfigurationManager

private static ConfigurationManager _instance;

private static readonly object _lock = new object(); // Lock

for thread safety

private ConfigurationManager() { } // Private constructor to

prevent instantiation

public static ConfigurationManager Instance

get

lock (_lock) // Ensure thread safety

return _instance ??= new ConfigurationManager(); //

Lazy initialization

Follow:

public string GetSetting(string key) => "some value"; // Example

method to return a setting

  • Private Constructor:
  • The constructor is private, preventing external code from creating instances

directly. This ensures that the class cannot be instantiated more than once.

  • Static Instance Property:
  • The Instance property is used to access the unique instance of

ConfigurationManager. It uses lazy initialization to create the instance

only when it's first needed.

  • Thread Safety:
  • The lock (_lock) statement ensures that the instance creation is

thread-safe, preventing multiple threads from creating multiple instances at

the same time in a multithreaded environment.

  • Lazy Initialization (??=):
  • The ??= operator ensures that the instance is only created if it's null,

ensuring that the instance is created only once and reused thereafter.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Builder Pattern separates the construction of a complex object from its

representation. You can change the construction process without changing

the way the object is represented or structured.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Interpreter Pattern is ideal for scenarios where the grammar is complex

and subject to change. By defining expressions as objects, it’s easy to extend

or modify the grammar without affecting other parts of the system.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The example above demonstrates shallow cloning, where only the primitive

properties are copied. If the object contains references to other objects (e.g.,

arrays, lists), you may need to implement deep cloning to ensure that

referenced objects are also cloned, not just referenced.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Singleton class (ConfigurationManager) only allows one instance to

be created. The instance is stored in the static _instance field, ensuring

that only one object exists.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Shape class is the abstraction. It holds a reference to the

IDrawingAPI and delegates the drawing task to it. It defines the common

interface Draw() that all shapes must implement.

public abstract class Shape

protected IDrawingAPI _drawingAPI;

protected Shape(IDrawingAPI drawingAPI) => _drawingAPI =

drawingAPI;

public abstract void Draw();

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Cook method in the Recipe class defines the skeleton of the algorithm.

It calls GatherIngredients, Prepare, CookMethod, and Serve in a fixed

order. The first three steps are abstract and need to be implemented by

subclasses, while the Serve method is concrete and always works the same

way.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Calculator applications that need to parse and evaluate mathematical

expressions like 5 + 3 * 2 can leverage the Interpreter Pattern to handle

different operators and operands. Each part of the expression (numbers,

operators) is represented as an object that can be evaluated.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • SQL queries consist of complex expressions (e.g., SELECT, WHERE, JOIN).

The Interpreter Pattern can be used to build a query parser that interprets

the structure and conditions in the query, eventually transforming them into an

executable SQL statement.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The pattern is ideal for implementing undo functionality because it allows the

system to keep a history of states and revert back to any previous state.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The TextMemento captures the state of the TextEditor object (in this

case, the text content). It doesn't expose any internal details of the

TextEditor, preserving encapsulation.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The current implementation doesn't handle errors (e.g., invalid expressions).

It’s advisable to add error-checking mechanisms (e.g., checking for division

by zero, invalid operators, etc.) to make the interpreter more robust.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • You can easily add new shapes or drawing styles without changing existing

classes. This is particularly useful in scenarios where the number of shapes

or rendering methods can grow over time.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The instance is created only when needed, reducing the overhead of

initialization when the object is not used. This ensures that resources are

used efficiently.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Observers can be added or removed at runtime, allowing dynamic changes to

the system based on user actions or conditions.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The client code doesn't need to know the internal implementation of the

collection (e.g., whether it's a list or a tree). It can use the iterator interface to

access the elements sequentially, leading to cleaner and more maintainable

code.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Used to represent an object that is located on a different machine (e.g., over a

network), and it handles communication between the client and the remote

object.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • A proxy can control access to the real object, ensuring that actions like

creation, deletion, or other operations are performed only when appropriate.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In graphical user interfaces (GUIs), iterating through a complex hierarchical

menu structure can be achieved using the Iterator Pattern. Each menu can

be an aggregate, and each menu item can be iterated over using an iterator.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The NewsSubscriber class represents an observer. Each subscriber listens

to the publisher and updates its state (in this case, by printing the news) when

the publisher notifies them.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • For multi-threaded environments, ensuring safe iteration over collections

might require synchronized access to the collection. The iterator can be

modified to handle concurrency issues.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • By using the builder, you can add more ingredients or properties in a fluent

manner (i.e., chaining method calls), which can make the code cleaner and

more readable.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Each user communicates with the mediator, not with other users directly.

When a user sends a message, the mediator handles the responsibility of

broadcasting that message to other users.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The mediator controls the communication between all the colleagues, which

makes it easier to modify or extend how messages are passed. For example,

adding new features like message filtering or logging can be done in the

mediator without affecting the users.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In air traffic control systems, the Mediator Pattern can be used to handle

communication between different planes and the control tower. The control

tower acts as the mediator, relaying necessary information and ensuring that

planes don’t directly communicate with each other, reducing the chances of

collision or confusion.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • When a log message is passed to the infoLogger, it checks if it can handle

the message. If the message level is Info, it processes the message. If not,

it passes the request to the next handler (errorLogger).

Follow:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • For large systems with a high number of components, the mediator itself

might become complex and difficult to maintain. It's essential to manage its

complexity to avoid it becoming a bottleneck or overly complicated.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The TextEditor class represents the originator in the Memento Pattern. It has the

actual state (the text) and provides methods to change the state, save the current

state to a Memento, and restore a previous state from a Memento.

  • The Save() method creates a new TextMemento capturing the current state of the

editor.

  • The Restore() method restores the editor's state from a given TextMemento.

public class TextEditor

private string _text;

public void Write(string text) => _text = text;

public TextMemento Save() => new TextMemento(_text);

public void Restore(TextMemento memento) => _text =

memento.Text;

public override string ToString() => _text;

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The chain of responsibility can be dynamically configured by adding or

removing handlers at runtime. This makes it flexible to change the behavior of

the system without modifying the request-handling code.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The pattern introduces additional classes (visitors), which can make the

system more complex, especially when the number of elements and visitors

increases.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

the existing classes.

Follow:

  • This pattern allows you to keep your object classes stable and add

functionality through new visitor classes.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The proxy controls access to the real object, initializing it only when needed.

This is known as lazy loading. For example, the large image is only loaded

when the client requests it for the first time.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The TextEditor is responsible for executing the command. It calls the

Execute() method of the command, which in turn delegates the action to

the Document class (the receiver).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Command Pattern is particularly useful for implementing undo/redo

functionality. The stack of executed commands allows for easy reversion of

actions without needing to track individual changes manually.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The IShoppingCartElement interface declares the Accept method, which allows

the element to accept a visitor. Each element (like Book, Fruit) will implement this

interface to allow a visitor to operate on it.

public interface IShoppingCartElement

void Accept(IShoppingCartVisitor visitor);

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • For complex operations, you might want to implement batch command

execution. Multiple commands can be grouped together, and executing or

undoing the entire batch can be done in a single operation.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • If the template method involves a large number of steps, or if there are many

subclasses with different variations of steps, the code can become harder to

manage and maintain.

Conclusion:

The Template Method Pattern is a powerful way to define the structure of an algorithm

while allowing subclasses to customize specific steps. It's ideal when you want to reuse a

Follow:

common workflow while providing flexibility to modify particular steps. It is frequently used in

frameworks and libraries, where the overall process must remain consistent, but certain

aspects can be customized or extended. This pattern ensures that the general algorithm

remains the same while giving subclasses the freedom to tailor specific steps to their needs.

Visitor Pattern: Adding New Operations Without Modifying Object

Structures

Definition:

The Visitor Pattern separates an algorithm from the object structure on which it operates. It

allows you to add new operations to existing object structures without modifying the

structures themselves. Instead of embedding operations directly into the objects, you define

a visitor that knows how to operate on each type of object in the structure.

Use Case:

A typical use case for the Visitor Pattern is calculating taxes or discounts for different

product types in a shopping cart. Each product type (e.g., books, fruits, electronics) might

require different calculations, and the Visitor Pattern allows you to easily add new types of

operations (e.g., tax calculation, discount application) without altering the objects in the

shopping cart.

Code Breakdown:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The File class is a leaf node in the composite structure. It doesn’t contain

any child components but implements the ShowInfo() method to display its

name.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • You can easily add new types of components (e.g., a SymbolicLink class

or a Shortcut class) to the system without affecting the existing code. As

long as the new class implements the IFileSystemComponent interface, it

will fit seamlessly into the existing structure.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The visitor interface defines a visit method for each type of element. Each

Visit method encapsulates the operation to be performed on the

corresponding element.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In graphical user interface (GUI) applications, prototypes could be used to

clone UI components (e.g., buttons, text fields) with predefined styles or

settings.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Prototype Pattern is best suited for cases where cloning makes sense. If

object creation doesn't involve copying or if it requires significant setup, the

pattern might not be appropriate.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In graphic design tools, shapes can be composed into larger structures (like a

group of shapes). Each shape (a circle, a rectangle, etc.) can be treated as

an individual object, while a group of shapes can be treated as a composite

object. The Composite Pattern makes it easier to manage complex graphical

objects that contain simple shapes.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Memento must contain only the necessary state of the object. If the state

is complex (e.g., involving many interdependencies), it may be difficult to

capture it in a Memento without violating encapsulation or increasing

complexity.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In addition to ShowInfo(), you could add other methods to traverse the

structure in different ways, such as depth-first or breadth-first traversal.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • If you are creating a framework where clients need to customize only certain

steps of a predefined process, the Template Method Pattern allows them to

override the necessary methods while ensuring the common workflow

remains intact.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • SimpleCoffee is the core object that implements ICoffee. It has a fixed

price and a basic description. This is the base coffee that we will add features

to dynamically.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • You can add new operations (like taxes or shipping costs) by simply creating

new visitor classes without needing to modify the existing elements (Book,

Fruit). This makes it easier to extend functionality in the future.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Subclasses, like PastaRecipe, implement the GatherIngredients,

Prepare, and CookMethod methods. These methods contain the specific

Follow:

details of the recipe, such as the ingredients, preparation steps, and cooking

process.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • A remote proxy can be used to handle communication between a client and a

remote server, managing the complexities of network protocols and making it

seem as if the remote object is local.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Decorator Pattern is widely used in UI design. For example, you can

decorate a button with additional features (like borders, shadows, or icons)

dynamically. You don't need to subclass the button every time you want to

add new functionality.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • When an object's behavior changes dynamically, and the change can be

achieved by selecting different algorithms.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • If the coffee is highly customizable, you could add additional logic to the

Cost() method to calculate discounts or offer combo prices (e.g., a discount

when multiple ingredients are added).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • For each algorithm, you need a separate class. This could lead to an increase

in the number of classes in your application, which might not be desirable in

simpler systems.

Follow:

Conclusion:

The Strategy Pattern is an excellent choice for applications that need to support multiple

interchangeable algorithms. By encapsulating algorithms in separate strategy classes and

delegating the task to the context, you avoid conditional statements and make your code

more flexible, maintainable, and extensible. It's especially useful in scenarios like sorting,

different payment methods, or compression algorithms where the behavior of the object

varies based on the strategy being used.

Template Method Pattern: Defining the Skeleton of an Algorithm

Definition:

The Template Method Pattern defines the skeleton of an algorithm in a method, deferring

some steps to subclasses. This pattern lets subclasses redefine certain steps of an

algorithm without changing the overall structure of the algorithm. Essentially, the Template

Method sets the "template" or the common sequence of steps, while allowing subclasses to

provide specific implementations for some of the steps.

Use Case:

A typical use case for the Template Method Pattern is creating a framework for a

cooking recipe where every recipe follows a similar structure (e.g., gather ingredients,

prepare, cook, and serve), but the actual details of each step can vary depending on the

type of recipe.

Code Breakdown:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The HomeTheaterFacade class simplifies the process by offering two

high-level methods: WatchMovie() and EndMovie(). These methods

internally call the relevant methods on the subsystem components (e.g., On()

for the amplifier, Play() for the DVD player). The user doesn’t need to deal

with the details of how the components interact or manage their state.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Without the strategy pattern, you might need to use complex conditionals (like

if-else or switch) to determine which algorithm to use. The strategy

pattern eliminates this by encapsulating the algorithm in separate classes.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Prototype Pattern allows you to create new objects dynamically, based

on the state of existing ones, without knowing the specific class of the object

you're cloning. This can be useful for creating different variations of an object

without manually specifying each one.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In e-commerce applications, a Facade can unify processes like checking out,

payment, inventory management, and shipping. A single checkout process

could internally handle all these complex operations.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • If the state machine is simple, using the State Pattern might be overkill.

Sometimes, basic conditionals (e.g., if/else) might suffice, and the pattern

may add unnecessary complexity.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In a more advanced scenario, you could make the methods in the facade

asynchronous, allowing components (like the DVD player) to load or process

content in the background, improving user experience.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The RealImage class implements the IImage interface and represents the actual

object that we want to control access to. It contains the logic to load and display the

image.

public class RealImage : IImage

private readonly string _filename;

public RealImage(string filename) => _filename = filename;

public void Display() => Console.WriteLine($"Displaying

{_filename}");

  • Behavior:
  • The RealImage object is only loaded once the Display() method is called.

This behavior can be resource-intensive, especially if the image is large.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • When an object’s behavior changes significantly with each state, and

transitioning between states needs to be managed cleanly and without

complex conditionals.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The concrete factories extend LoggerFactory and override the

CreateLogger method to create specific logger types, such as

FileLogger or ConsoleLogger. The subclass provides the implementation

details for object creation.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The PastaRecipe class is a concrete subclass that implements the specific details

of the steps defined in the abstract Recipe class. The steps like gathering

ingredients, preparing, and cooking are all tailored to pasta.

public class PastaRecipe : Recipe

protected override void GatherIngredients()

Console.WriteLine("Gathering pasta, sauce, and cheese.");

protected override void Prepare()

Console.WriteLine("Boiling pasta and preparing sauce.");

protected override void CookMethod()

Console.WriteLine("Cooking pasta with sauce.");

Follow:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Each concrete strategy (BubbleSort, QuickSort) implements the sorting

algorithm. These algorithms can be tested, optimized, or replaced without

Follow:

affecting the context or the other algorithms.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The GameCharacter class is a concrete implementation of the ICloneable

interface. It implements the Clone() method, which creates a new

GameCharacter object with the same properties as the original.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • This interface defines the Update() method, which will be implemented by concrete

observers. Each observer will receive updates from the subject when the state

changes.

public interface IObserver

void Update(string news);

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The IAggregate<T> interface is implemented by any collection that needs

to be iterated over. It provides the CreateIterator() method that returns

an iterator for that collection.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

Follow:

  • Since the Singleton class is globally accessible, it can be difficult to mock or

replace it in unit tests, leading to potential challenges in testing.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • You could extend this pattern to handle more complex object creation

processes. For example, factories might create loggers with specific

configurations, such as log levels (e.g., INFO, ERROR, DEBUG) or custom

output formats, allowing even more flexibility in how objects are created.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Each state (Red, Green, Yellow) implements the Change method differently,

providing specific behaviors for each state and defining how the transition to

the next state occurs.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

multiple Character objects to save memory.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The factory manages the extrinsic state (e.g., the position where the

character is rendered) separately. It ensures that intrinsic state (the symbol)

is shared between all instances, preventing the creation of duplicate objects.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • New platforms can be added by creating new concrete factories. The client

code doesn’t need to change; just use the new factory.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In scenarios with many similar objects, the pattern helps minimize the

overhead of object creation and garbage collection. This is particularly

beneficial in performance-sensitive applications like games or graphical user

interfaces.

Follow:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • A weather station where multiple devices (like smartphones or weather

dashboards) subscribe to receive updates on temperature, humidity, and

other weather conditions.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In games like Tetris or Minecraft, the board or world might contain many

repeated elements (e.g., the same type of tiles or blocks). Using the Flyweight

Pattern, you can create a single object for each tile type and reuse it across

multiple grid locations, saving memory.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Instance property provides global access to the single instance of the

class. This property ensures that no new instances are created, and the same

instance is returned every time.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • When using the Flyweight pattern in a multithreaded environment, care

should be taken to ensure thread safety. The flyweight factory could use a

concurrent dictionary or apply locking mechanisms to prevent concurrent

access to the shared flyweight objects.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Number class is a terminal expression that holds a single value. When

the Interpret method is called, it returns the value of the number.

  • Terminal expressions represent the simplest elements in the language or

grammar.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

Review the concept and prepare a concise verbal explanation with a real project example.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The object’s behavior changes dynamically as it transitions between states.

The client code doesn't need to manage state transitions; it's handled by the

state objects themselves.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • When there’s a need for a global logging mechanism where all parts of the

application log to the same destination (e.g., a log file or a central logging

service).

Follow:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In video games, the Memento Pattern can be used to save the game state

(such as player position, inventory, etc.) so that the player can undo or restore

their progress to a previous save point.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

Follow:

  • The pattern allows for recursive evaluation of expressions. Complex

expressions can be broken down into simpler expressions, and the results of

those can be combined to form more complex evaluations.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Interpreter Pattern is commonly used in building parsers for

domain-specific languages (DSLs) or simple programming languages. Each

statement or expression in the language can be represented as an object,

and the interpreter evaluates these statements to execute the program.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Interpreter Pattern can be extended to support more complex

grammars. For example, adding new operations like subtraction or division

can be easily done by introducing new non-terminal expressions (e.g.,

Subtract, Divide).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The separation of concerns means that any changes to the rendering logic

(e.g., upgrading the drawing API) do not affect the shape logic, and vice

versa. This results in less risk of introducing bugs when making changes.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The ProductIterator class implements the IIterator<Product>

interface and keeps track of the current position in the

ProductCollection. It knows how to traverse the collection, check if

there’s a next item (HasNext()), and return the next item (Next()).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Iterator Pattern allows the collection’s internal structure to be hidden

from the client. The client interacts only with the iterator, which means that

changes to the underlying collection (e.g., changing it from a list to a linked

list) do not affect the client code.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The IPizzaBuilder interface defines the steps for constructing a pizza. It

includes methods for setting the dough, sauce, and adding toppings, as well

as a Build() method to return the fully constructed pizza.

public interface IPizzaBuilder

void SetDough(string dough);

void SetSauce(string sauce);

void AddTopping(string topping);

Pizza Build();

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • When querying a database, the results often come back in the form of a

collection (like a list of rows). The Iterator Pattern is used to iterate over

these rows to access the data, rather than exposing the internal structure of

how the data is retrieved from the database.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • For very large collections, optimizing the iterator to handle bulk operations

efficiently (e.g., lazy loading or batching) can improve performance.

Visual Diagram:

Follow:

+---------------------------+

| IIterator<T> |

| (Iterator Interface) |

+---------------------------+

+---------------------------+

| |

+-----------------+ +------------------+

| ProductIterator| | ProductCollection|

| (Concrete Iterator) | (Concrete Aggregate)|

+-----------------+ +------------------+

| |

+--------------+ +--------------+

| HasNext() | | Add() |

| Next() | | Count |

| | | CreateIterator() |

+--------------+ +--------------+

Conclusion:

The Iterator Pattern is a powerful design pattern for accessing elements of a collection

sequentially, encapsulating the iteration logic in a separate object. This allows for greater

flexibility and maintainability by decoupling the collection's internal representation from the

client code.

Mediator Pattern: Real-Time Example - Chat Application

Definition:

The Mediator Pattern defines an object that encapsulates how a set of objects interact. It

promotes loose coupling by preventing objects from referring to each other explicitly,

allowing them to communicate indirectly through the mediator. This pattern is useful when

you need to manage complex interactions between multiple objects, without them needing to

know about each other.

Use Case:

Follow:

A chat application is a perfect example of where the Mediator Pattern can be applied. In a

chat app, users (colleagues) need to communicate, but rather than each user being directly

aware of the others, a mediator handles all the communication between users.

Code Explanation:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • New steps can easily be added to the template algorithm by updating the

abstract class. Additionally, the order and structure of steps remain consistent

across different subclasses.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The ChatMediator class is the concrete mediator that implements

IChatMediator. It manages a list of users and is responsible for

broadcasting messages to all registered users, except the one who sent the

message.

  • The mediator decouples the user objects from each other, so they don't need

to know about each other's existence.

public class ChatMediator : IChatMediator

private readonly List<User> _users = new List<User>();

public void RegisterUser(User user) => _users.Add(user);

Follow:

public void SendMessage(string message, User user)

foreach (var u in _users)

// Message should not be sent to the user who sent it

if (u != user)

u.Receive(message);

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Since each handler is responsible for a specific task (in this case, logging a

specific level of message), it’s easier to modify or extend the system. For

example, adding a new log level (e.g., Debug) would only require creating a

new handler for that level without affecting existing code.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Controls access to a resource by adding authorization checks before access

is allowed. It can act as a gatekeeper for resources.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • All observers receive the update from the subject automatically, ensuring that

they all stay in sync with the subject’s state.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Users don’t need to know the identities of other users or how to reach them.

The mediator centralizes communication, and the users only rely on the

mediator to send and receive messages.

Benefits of the Mediator Pattern:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The InfoLogger and ErrorLogger are concrete handlers that implement

the Logger class. Each handler checks if it can handle a particular log level

Follow:

(e.g., Info or Error). If it can, it processes the log; otherwise, it passes it along

to the next handler in the chain.

public class InfoLogger : Logger

protected override bool CanHandle(LogLevel level) => level ==

LogLevel.Info;

protected override void Handle(string message) =>

Console.WriteLine($"Info: {message}");

public class ErrorLogger : Logger

protected override bool CanHandle(LogLevel level) => level ==

LogLevel.Error;

protected override void Handle(string message) =>

Console.WriteLine($"Error: {message}");

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Instead of having complex direct interactions between objects (users in this

case), the mediator simplifies the process, as objects only need to

Follow:

communicate with the mediator.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • In a graphical user interface (GUI) system, the Mediator Pattern can be used

to manage interactions between various components like buttons, text fields,

and labels. For example, clicking a button might update a text field, and the

mediator ensures that these updates are propagated correctly.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

.LogMessage(...)).

This continues until a handler processes the message or the chain is

exhausted.

Key Benefits of the Chain of Responsibility Pattern:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • While the mediator reduces direct dependencies between colleagues, it can

also create a dependency on the mediator itself. Over-reliance on the

mediator can lead to issues if the mediator needs to change.

Visual Diagram:

+----------------------+

| IChatMediator |

| (Mediator Interface) |

+----------------------+

+------------------------------------+

| |

+------------------+ +------------------+

| ChatMediator | | User |

| (Concrete Mediator) | (Colleague) |

+------------------+ +------------------+

| |

+-------------------+ +------------------+

| RegisterUser(User)| | Send(string) |

| SendMessage(...) | | Receive(string) |

+-------------------+ +------------------+

Follow:

Conclusion:

The Mediator Pattern is an excellent solution for managing complex interactions between

objects in a system, particularly when those objects don’t need to know about each other

directly. It reduces dependencies, simplifies communication, and centralizes control, making

it easier to manage interactions. However, it should be used judiciously, as a poorly

implemented mediator can become a bottleneck or a single point of failure in the system.

Memento Pattern: Real-Time Example - Undo Feature in a Text Editor

Definition:

The Memento Pattern is used to capture and externalize an object's internal state without

violating encapsulation. This allows the object to be restored to this state later. It’s commonly

used in situations where an object's state changes over time and you may need to revert to

previous states, such as an undo feature.

Use Case:

The Memento Pattern is widely used in scenarios where you want to implement an undo or

restore functionality, such as in a text editor. In this case, the pattern allows the editor to

save versions of the text and restore them when the user requests an undo.

Code Breakdown:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The Caretaker is responsible for managing the saved states (mementos). It

can undo changes by restoring the TextEditor to its previous state stored

in the mementos stack.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • By avoiding the creation of heavy objects until they're needed, proxies can

improve the performance of applications, especially in cases of large datasets

or expensive operations (like network calls or file loading).

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • Once the real object is initialized, the proxy delegates the call to the real

object. In our example, after the image is loaded by the proxy, it delegates the

Display() method to the RealImage class.

Benefits of the Proxy Pattern:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The ProxyImage class also implements the IImage interface and controls access

to the RealImage. It is responsible for lazy loading the real image only when needed

(i.e., the first time Display() is called).

Follow:

public class ProxyImage : IImage

private readonly string _filename;

private RealImage _realImage;

public ProxyImage(string filename) => _filename = filename;

public void Display()

if (_realImage == null)

_realImage = new RealImage(_filename);

_realImage.Display();

  • Behavior:
  • The proxy holds a reference to a RealImage and initializes it only when the

Display() method is called for the first time. This delays the loading of the

image, making it more efficient if the Display() method is not called

frequently.

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • When the publisher publishes new news via the Notify() method, each

observer’s Update() method is called, and the news is sent to all registered

subscribers.

Benefits of the Observer Pattern:

Permalink

Gang of Four Patterns Design Patterns in C# · GoF Patterns

  • The AddTextCommand is a concrete implementation of the ICommand

interface. It encapsulates the request to add text to the document.

  • The Execute() method adds the specified text to the document, and the

Undo() method removes that text.

public class AddTextCommand : ICommand

private readonly Document _document;

private readonly string _text;

public AddTextCommand(Document document, string text)

_document = document;

_text = text;

public void Execute() => _document.AddText(_text);

public void Undo() => _document.RemoveText(_text);

Permalink