Design Patterns in .NET Core and Their Alternatives

In .NET Core, design patterns are commonly used as alternatives to complex code structures like large if-else blocks, tight coupling, duplicated logic, and difficult-to-maintain code.

Design Pattern Alternative For Purpose
Factory Pattern Large if-else / switch statements Centralizes object creation logic
Strategy Pattern Behavior-based if-else conditions Makes algorithms interchangeable
State Pattern Complex state condition checks Encapsulates state-specific behavior
Command Pattern Direct method calls Decouples request from execution
Repository Pattern Scattered database queries Abstracts data access logic
Unit of Work Multiple transaction handling Centralizes transaction management
Dependency Injection Frequent use of new keyword Provides loose coupling
Singleton Pattern Global static objects Ensures single instance creation
Observer Pattern Tightly coupled event handling Implements publish-subscribe model
Decorator Pattern Large inheritance hierarchies Adds behavior dynamically
Adapter Pattern Incompatible interfaces Connects incompatible classes
Facade Pattern Complex subsystem calls Provides simplified interface
Builder Pattern Constructors with many parameters Builds complex objects step-by-step
Prototype Pattern Repeated object creation Clones existing objects
Mediator Pattern Direct communication between objects Centralizes communication
Chain of Responsibility Nested validations/checks Processes requests through handlers
Template Method Duplicate workflow logic Reuses common algorithm structure
Specification Pattern Repeated filtering conditions Creates reusable query rules
CQRS Single bloated service layer Separates read and write operations

Examples

1. Factory Pattern

Alternative for: if-else object creation

if(type == "pdf")
    service = new PdfService();
else if(type == "excel")
    service = new ExcelService();

Using Factory:

var service = reportFactory.Create(type);

2. Strategy Pattern

Alternative for: behavior-based conditions

if(paymentType == "Card")
    ProcessCard();
else if(paymentType == "UPI")
    ProcessUPI();

Using Strategy:

paymentStrategy.Process();

3. Builder Pattern

Alternative for: constructors with too many parameters

new User("John", 25, true, "Admin", "India");

Using Builder:

var user = new UserBuilder()
    .WithName("John")
    .WithAge(25)
    .Build();

Conclusion

Design patterns in .NET Core are mainly alternatives for:

  • Large if-else blocks
  • Tight coupling
  • Repeated code
  • Complex object creation
  • Difficult testing
  • Rigid architecture

Using proper design patterns makes applications more scalable, maintainable, reusable, and testable.

Examples of Design Patterns in .NET Core

1. Factory Pattern

Alternative for: Large if-else or switch statements

if(type == "pdf")
    service = new PdfService();
else if(type == "excel")
    service = new ExcelService();

Using Factory:

var service = reportFactory.Create(type);

2. Strategy Pattern

Alternative for: Behavior-based if-else conditions

if(paymentType == "Card")
    ProcessCard();
else if(paymentType == "UPI")
    ProcessUPI();

Using Strategy:

paymentStrategy.Process();

3. State Pattern

Alternative for: State-based condition checking

if(order.Status == "Pending")
    Approve();
else if(order.Status == "Shipped")
    Deliver();

Using State Pattern:

orderState.Handle(order);

4. Command Pattern

Alternative for: Direct method calls

button.Click += SaveFile;

Using Command:

ICommand command = new SaveCommand();
command.Execute();

5. Repository Pattern

Alternative for: Direct database queries everywhere

var users = _context.Users.ToList();

Using Repository:

var users = userRepository.GetAll();

6. Unit of Work Pattern

Alternative for: Multiple scattered SaveChanges()

_context.Users.Add(user);
_context.SaveChanges();

_context.Orders.Add(order);
_context.SaveChanges();

Using Unit of Work:

unitOfWork.Users.Add(user);
unitOfWork.Orders.Add(order);

unitOfWork.Commit();

7. Dependency Injection

Alternative for: Frequent use of new keyword

var service = new EmailService();

Using DI:

public UserController(IEmailService service)
{
    _service = service;
}

8. Singleton Pattern

Alternative for: Global static objects

public static Logger logger = new Logger();

Using Singleton:

var logger = Logger.Instance;

9. Observer Pattern

Alternative for: Tight event coupling

user.SendEmail();
user.SendSMS();

Using Observer:

publisher.NotifySubscribers();

10. Decorator Pattern

Alternative for: Large inheritance hierarchy

class PremiumCoffee : MilkCoffee

Using Decorator:

coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);

11. Adapter Pattern

Alternative for: Incompatible interfaces

OldPaymentGateway.Pay();

Using Adapter:

adapter.ProcessPayment();

12. Facade Pattern

Alternative for: Complex subsystem calls

cpu.Start();
memory.Load();
disk.Read();

Using Facade:

computer.Start();

13. Builder Pattern

Alternative for: Constructors with many parameters

new User("John", 25, true, "Admin");

Using Builder:

var user = new UserBuilder()
    .WithName("John")
    .WithAge(25)
    .Build();

14. Prototype Pattern

Alternative for: Recreating same object repeatedly

var user = new User();

Using Prototype:

var clonedUser = existingUser.Clone();

15. Mediator Pattern

Alternative for: Objects communicating directly

user.Notify(admin);
admin.Notify(manager);

Using Mediator:

mediator.SendMessage(message);

16. Chain of Responsibility

Alternative for: Nested validations

if(isValidUser)
{
    if(hasPermission)
    {
        if(isActive)
        {
        }
    }
}

Using Chain Pattern:

handler.Handle(request);

17. Template Method

Alternative for: Duplicate workflow logic

ProcessCSV();
ProcessExcel();

Using Template Method:

processor.ProcessFile();

18. Specification Pattern

Alternative for: Repeated filtering conditions

users.Where(x => x.IsActive && x.Age > 18);

Using Specification:

repository.Find(activeAdultSpecification);

19. CQRS Pattern

Alternative for: One large service handling everything

UserService.CreateUser();
UserService.GetUsers();

Using CQRS:

CreateUserCommand
GetUsersQuery

Summary

Design patterns are mainly alternatives for:

  • Large if-else blocks
  • Tight coupling
  • Code duplication
  • Complex constructors
  • Scattered database logic
  • Hard-to-maintain architecture

Comments

Popular posts from this blog

Promises in Angular

Debouncing & Throttling in RxJS: Optimizing API Calls and User Interactions

Csharp Coding - Session