Technical interview questions with detailed answers—organized by course, like Dot Net Tutorials interview sections. Original content for Toolliyo Academy.
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.
Tip: Keep answers under 90 seconds unless the interviewer asks for depth. Practice aloud on Toolliyo before your mock interview.
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.
Tip: Keep answers under 90 seconds unless the interviewer asks for depth. Practice aloud on Toolliyo before your mock interview.
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.
Tip: Keep answers under 90 seconds unless the interviewer asks for depth. Practice aloud on Toolliyo before your mock interview.
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.
Tip: Keep answers under 90 seconds unless the interviewer asks for depth. Practice aloud on Toolliyo before your mock interview.
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.
Tip: Keep answers under 90 seconds unless the interviewer asks for depth. Practice aloud on Toolliyo before your mock interview.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
Review the concept and prepare a concise verbal explanation with a real project example.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
Review the concept and prepare a concise verbal explanation with a real project example.
Design Patterns & SOLID Design Patterns in C# · SOLID
concurrent environments.
Design Patterns & SOLID Design Patterns in C# · SOLID
Review the concept and prepare a concise verbal explanation with a real project example.
Design Patterns & SOLID Design Patterns in C# · SOLID
container, though generally discouraged.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
It's simple but can waste resources if the instance is never used.
resources but requires careful implementation for thread safety.
Factory pattern Q&A
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
decide which class to instantiate. It uses inheritance and relies on subclass
overriding.
objects without specifying their concrete classes. It uses composition and is useful
when you need to create multiple related objects together.
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
Design Patterns & SOLID Design Patterns in C# · SOLID
code.
concrete types.
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
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.
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
Design Patterns & SOLID Design Patterns in C# · SOLID
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.
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
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).
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();
Design Patterns & SOLID Design Patterns in C# · SOLID
Design Patterns & SOLID Design Patterns in C# · SOLID
IProductRepository)
public interface IProductRepository : IRepository<Product>
Task<IEnumerable<Product>> GetProductsWithLowStockAsync(int
threshold);
Design Patterns & SOLID Design Patterns in C# · SOLID
repository/unit-of-work pattern).
projections.
value.
Unit of Work
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.
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.
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>();
Design Patterns & SOLID Design Patterns in C# · SOLID
transaction.
(Complete()), improving control and readability.
instead of multiple repositories.
unnecessary database operations.
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)
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:
Principle)
Design Patterns & SOLID Design Patterns in C# · SOLID
Review the concept and prepare a concise verbal explanation with a real project example.
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.
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>();
Design Patterns & SOLID Design Patterns in C# · SOLID
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
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:
Design Patterns & SOLID Design Patterns in C# · SOLID
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
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)
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
You can identify SRP violations by asking questions like:
logic)?
ReportGeneratorAndPrinter.
Common signs:
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
SRP improves maintainability by:
code are kept apart.
Ultimately, it leads to more modular, flexible, and robust code.
Design Patterns & SOLID Design Patterns in C# · SOLID
If a class has multiple responsibilities:
Open/Closed Principle (OCP)
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
To design classes that follow OCP:
✅ Extend behavior through new classes rather than modifying existing code.
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.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
implement or inherit.
existing code.
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)
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
Violating LSP can lead to:
class.
abstractions.
Essentially, it defeats the purpose of polymorphism.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
To ensure subclasses follow LSP:
base class.
class behavior.
valid scenarios.
✅ Ask yourself: Can this subclass be used anywhere the base class is used — without
surprises?
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)
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
Small, specific interfaces:
In contrast, large interfaces force classes to implement methods they may not need —
leading to fragile and cluttered code.
Design Patterns & SOLID Design Patterns in C# · SOLID
ISP improves code flexibility by:
Smaller interfaces result in lower coupling and better maintainability.
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.
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)
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:
abstract classes.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
Abstractions (e.g., interfaces or abstract classes):
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.");
✅ 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.
Design Patterns & SOLID Design Patterns in C# · SOLID
✅ Key Benefits:
ones
containers
Advanced & Scenario-Based
Questions
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.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
Testing singletons/statics is tricky due to global state. Best practices include:
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.
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.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
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.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
Practical .NET Questions
Design Patterns & SOLID Design Patterns in C# · SOLID
ASP.NET Core MVC has built-in support for Dependency Injection.
IServiceCollection:
public void ConfigureServices(IServiceCollection services)
services.AddControllersWithViews();
services.AddScoped<IProductService, ProductService>(); //
Example
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
their lifetimes (Scoped, Transient, Singleton). It acts as a service registry.
registered services at runtime. It uses the registrations to create and inject
dependencies.
Design Patterns & SOLID Design Patterns in C# · SOLID
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConne
ction")));
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
var mockRepo = new Mock<IProductRepository>();
mockRepo.Setup(repo => repo.GetAll()).Returns(new List<Product> {
... });
var service = new ProductService(mockRepo.Object);
// Act & Assert
Design Patterns & SOLID Design Patterns in C# · SOLID
decides to pass control or handle the request.
or after.
pipeline setup.
Design Patterns & SOLID Design Patterns in C# · SOLID
public interface ICacheStrategy
void Cache(string key, object value);
object Retrieve(string key);
DistributedCacheStrategy.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
without specifying concrete classes.
Example: Creating UI components for different OS (Windows, Mac).
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
classes.
Design Patterns & SOLID Design Patterns in C# · SOLID
Design Patterns & SOLID Design Patterns in C# · SOLID
DIP by reducing direct dependencies.
modifying existing components.
Behavioral / Conceptual Questions
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.
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.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
Challenges include:
performant.
Design Patterns & SOLID Design Patterns in C# · SOLID
I use a combination of:
Patterns”.
maintainability.
Bonus / Miscellaneous
Design Patterns & SOLID Design Patterns in C# · SOLID
properties from a parent class. It can lead to tight coupling and fragile hierarchies if
overused.
other classes and delegates behavior to them. It’s more flexible and promotes loose
coupling.
Design Patterns & SOLID Design Patterns in C# · SOLID
their interface. It wraps the original object to extend behavior.
or logging, without changing its interface.
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.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
explicitly.
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.
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.
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
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.
Design Patterns & SOLID Design Patterns in C# · SOLID
means focused, well-defined responsibilities.
modules are independent and changes in one don’t affect others.
Design Patterns & SOLID Design Patterns in C# · SOLID
coupling.
Design Patterns & SOLID Design Patterns in C# · SOLID
allowing flexible implementations.
Template Method pattern and partial abstraction.
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.
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Optimizations such as memoization (caching results) can be used to avoid
redundant evaluations, particularly for recursive expressions.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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);
Gang of Four Patterns Design Patterns in C# · GoF Patterns
that all iterators implement the basic functionality of checking for the next
element (HasNext()) and returning the next element (Next()).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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)}";
Gang of Four Patterns Design Patterns in C# · GoF Patterns
result in significant memory usage, as you need to store many copies of the
state (each memento).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
additional functionality like removing items during iteration.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
of all users and broadcasts messages to all other users when one user sends
a message.
loose coupling.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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);
Gang of Four Patterns Design Patterns in C# · GoF Patterns
maintains a list of IObserver instances (subscribers) and provides methods
to add (Subscribe), remove (Unsubscribe), and notify them (Notify).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
same interface (IImage) as the real subject (RealImage).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
the state (the text content) and doesn’t allow direct manipulation of that state.
public class TextMemento
public string Text { get; }
public TextMemento(string text) => Text = text;
Follow:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
especially when dealing with high-resolution media files that could be costly to
load upfront.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
perform operations on them that vary.
complex hierarchy (like a shopping cart with various types of products), and
you need to add new behaviors without changing the objects themselves.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
operation, you could store the undone command in a separate stack and
allow users to redo the previous undo operation.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
will be implemented by both leaf and composite components.
public interface IFileSystemComponent
void ShowInfo();
Gang of Four Patterns Design Patterns in C# · GoF Patterns
from the objects on which it operates. This makes the object structure
(elements) cleaner, as they are not responsible for the business logic.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
■ 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);
Gang of Four Patterns Design Patterns in C# · GoF Patterns
mediator is responsible for sending messages between users. It ensures that
messages are routed correctly without the users needing to know about each
other.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
interface, which defines the common method ShowInfo(). This allows us to
treat both files and directories uniformly.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
IFileSystemComponent interface. This makes it easier to manage a mixed
structure of individual and composite objects.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Follow:
object (ProxyImage) implement. It defines the method Display() that both
concrete classes must implement.
public interface IImage
void Display();
Gang of Four Patterns Design Patterns in C# · GoF Patterns
components. It could be improved by adding a Remove() method to allow for
the dynamic removal of files or subdirectories.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
and Description() that every coffee component will implement.
public interface ICoffee
double Cost();
string Description();
Gang of Four Patterns Design Patterns in C# · GoF Patterns
This allows the decorators to work with any class that implements this
interface, providing flexibility to decorate any coffee object.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
the traffic light to transition between states (Red, Green, Yellow).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
over time and can save and restore its state using mementos.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
subclasses don't have to repeat the same steps. Only the details of specific
steps need to be implemented in each subclass.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
ChocolateDecorator, or CaramelDecorator, for a richer coffee
experience.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
especially when the object is complex or expensive to create. This can be
particularly useful in performance-sensitive applications like games or
simulations.
Follow:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Follow:
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
task and want to switch between them easily (e.g., sorting, encryption,
compression).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
with complex subsystems. The user only needs to interact with a few
high-level methods, making the system easier to use.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
algorithms is small, using the Strategy Pattern might be over-engineering.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.");
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
all types of loggers (e.g., file, console).
public interface ILogger
void Log(string message);
Gang of Four Patterns Design Patterns in C# · GoF Patterns
■ Execute(): Executes the command.
■ Undo(): Reverts the command if the user wishes to undo the action.
Follow:
public interface ICommand
void Execute();
void Undo();
Gang of Four Patterns Design Patterns in C# · GoF Patterns
returns an ILogger object. This is a generic interface for creating various
Follow:
logger types without specifying the concrete class directly.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
behavior depends on the current state (e.g., traffic lights, order processing
systems).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
grammar, allowing them to be interpreted (evaluated). Every class that
implements this interface will provide its own interpretation logic.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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();
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
to an increase in the number of classes in the system. For systems with many
states, this can cause complexity.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
of an object. Any class that needs to be cloned must implement this interface.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
actually needed, like the ProxyImage example above.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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);
the specific behavior of the traffic light for that state.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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})");
Gang of Four Patterns Design Patterns in C# · GoF Patterns
new articles or breaking news are published.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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;
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
implementation (drawing API) independently, providing a cleaner and more
modular design.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
challenging. Every new element requires modifying all existing visitor classes
to implement the new Visit method.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
state changes and can lead to issues with dependencies.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
It has a method Request() that the client expects to call.
public interface ITarget
void Request();
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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);
Gang of Four Patterns Design Patterns in C# · GoF Patterns
libraries without modifying their code. It enables compatibility between
incompatible interfaces.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
the application (e.g., database connection strings, file paths, API keys).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Review the concept and prepare a concise verbal explanation with a real project example.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
instance of it throughout the application.
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
directly. This ensures that the class cannot be instantiated more than once.
ConfigurationManager. It uses lazy initialization to create the instance
only when it's first needed.
thread-safe, preventing multiple threads from creating multiple instances at
the same time in a multithreaded environment.
ensuring that the instance is created only once and reused thereafter.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
representation. You can change the construction process without changing
the way the object is represented or structured.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
be created. The instance is stored in the static _instance field, ensuring
that only one object exists.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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();
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
system to keep a history of states and revert back to any previous state.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
case, the text content). It doesn't expose any internal details of the
TextEditor, preserving encapsulation.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
It’s advisable to add error-checking mechanisms (e.g., checking for division
by zero, invalid operators, etc.) to make the interpreter more robust.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
classes. This is particularly useful in scenarios where the number of shapes
or rendering methods can grow over time.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
initialization when the object is not used. This ensures that resources are
used efficiently.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
the system based on user actions or conditions.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
network), and it handles communication between the client and the remote
object.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
creation, deletion, or other operations are performed only when appropriate.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
to the publisher and updates its state (in this case, by printing the news) when
the publisher notifies them.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
might require synchronized access to the collection. The iterator can be
modified to handle concurrency issues.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
manner (i.e., chaining method calls), which can make the code cleaner and
more readable.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
When a user sends a message, the mediator handles the responsibility of
broadcasting that message to other users.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
the message. If the message level is Info, it processes the message. If not,
it passes the request to the next handler (errorLogger).
Follow:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
might become complex and difficult to maintain. It's essential to manage its
complexity to avoid it becoming a bottleneck or overly complicated.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
editor.
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;
Gang of Four Patterns Design Patterns in C# · GoF Patterns
removing handlers at runtime. This makes it flexible to change the behavior of
the system without modifying the request-handling code.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
system more complex, especially when the number of elements and visitors
increases.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
the existing classes.
Follow:
functionality through new visitor classes.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
This is known as lazy loading. For example, the large image is only loaded
when the client requests it for the first time.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Execute() method of the command, which in turn delegates the action to
the Document class (the receiver).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
functionality. The stack of executed commands allows for easy reversion of
actions without needing to track individual changes manually.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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);
Gang of Four Patterns Design Patterns in C# · GoF Patterns
execution. Multiple commands can be grouped together, and executing or
undoing the entire batch can be done in a single operation.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
any child components but implements the ShowInfo() method to display its
name.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Visit method encapsulates the operation to be performed on the
corresponding element.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
clone UI components (e.g., buttons, text fields) with predefined styles or
settings.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
object creation doesn't involve copying or if it requires significant setup, the
pattern might not be appropriate.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
is complex (e.g., involving many interdependencies), it may be difficult to
capture it in a Memento without violating encapsulation or increasing
complexity.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
structure in different ways, such as depth-first or breadth-first traversal.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
steps of a predefined process, the Template Method Pattern allows them to
override the necessary methods while ensuring the common workflow
remains intact.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
price and a basic description. This is the base coffee that we will add features
to dynamically.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
new visitor classes without needing to modify the existing elements (Book,
Fruit). This makes it easier to extend functionality in the future.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Prepare, and CookMethod methods. These methods contain the specific
Follow:
details of the recipe, such as the ingredients, preparation steps, and cooking
process.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
remote server, managing the complexities of network protocols and making it
seem as if the remote object is local.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
achieved by selecting different algorithms.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Cost() method to calculate discounts or offer combo prices (e.g., a discount
when multiple ingredients are added).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
if-else or switch) to determine which algorithm to use. The strategy
pattern eliminates this by encapsulating the algorithm in separate classes.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
payment, inventory management, and shipping. A single checkout process
could internally handle all these complex operations.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Sometimes, basic conditionals (e.g., if/else) might suffice, and the pattern
may add unnecessary complexity.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
asynchronous, allowing components (like the DVD player) to load or process
content in the background, improving user experience.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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}");
This behavior can be resource-intensive, especially if the image is large.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
transitioning between states needs to be managed cleanly and without
complex conditionals.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
CreateLogger method to create specific logger types, such as
FileLogger or ConsoleLogger. The subclass provides the implementation
details for object creation.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
algorithm. These algorithms can be tested, optimized, or replaced without
Follow:
affecting the context or the other algorithms.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
interface. It implements the Clone() method, which creates a new
GameCharacter object with the same properties as the original.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
observers. Each observer will receive updates from the subject when the state
changes.
public interface IObserver
void Update(string news);
Gang of Four Patterns Design Patterns in C# · GoF Patterns
to be iterated over. It provides the CreateIterator() method that returns
an iterator for that collection.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Follow:
replace it in unit tests, leading to potential challenges in testing.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
providing specific behaviors for each state and defining how the transition to
the next state occurs.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
multiple Character objects to save memory.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
character is rendered) separately. It ensures that intrinsic state (the symbol)
is shared between all instances, preventing the creation of duplicate objects.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
code doesn’t need to change; just use the new factory.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
overhead of object creation and garbage collection. This is particularly
beneficial in performance-sensitive applications like games or graphical user
interfaces.
Follow:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
dashboards) subscribe to receive updates on temperature, humidity, and
other weather conditions.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
class. This property ensures that no new instances are created, and the same
instance is returned every time.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
the Interpret method is called, it returns the value of the number.
grammar.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Review the concept and prepare a concise verbal explanation with a real project example.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
The client code doesn't need to manage state transitions; it's handled by the
state objects themselves.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
application log to the same destination (e.g., a log file or a central logging
service).
Follow:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
(such as player position, inventory, etc.) so that the player can undo or restore
their progress to a previous save point.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
Follow:
expressions can be broken down into simpler expressions, and the results of
those can be combined to form more complex evaluations.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
grammars. For example, adding new operations like subtraction or division
can be easily done by introducing new non-terminal expressions (e.g.,
Subtract, Divide).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
(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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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()).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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();
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
abstract class. Additionally, the order and structure of steps remain consistent
across different subclasses.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
IChatMediator. It manages a list of users and is responsible for
broadcasting messages to all registered users, except the one who sent the
message.
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);
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
is allowed. It can act as a gatekeeper for resources.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
they all stay in sync with the subject’s state.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
The mediator centralizes communication, and the users only rely on the
mediator to send and receive messages.
Benefits of the Mediator Pattern:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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}");
Gang of Four Patterns Design Patterns in C# · GoF Patterns
case), the mediator simplifies the process, as objects only need to
Follow:
communicate with the mediator.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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.
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:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
can undo changes by restoring the TextEditor to its previous state stored
in the mementos stack.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
improve the performance of applications, especially in cases of large datasets
or expensive operations (like network calls or file loading).
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
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();
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.
Gang of Four Patterns Design Patterns in C# · GoF Patterns
observer’s Update() method is called, and the news is sent to all registered
subscribers.
Benefits of the Observer Pattern:
Gang of Four Patterns Design Patterns in C# · GoF Patterns
interface. It encapsulates the request to add text to the document.
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);