Skip to content
~/writing
.NET

Popular design patterns in .NET

/ 1 min read / Ejan Shrestha

Design patterns are essential tools in the arsenal of every .NET developer. They provide proven solutions to recurring design problems, promote code reusability, and improve maintainability. In this blog post, we'll explore three popular design patterns commonly used in .NET development: Singleton, Factory, and Observer.

Singleton Pattern

The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance. This pattern is useful when exactly one object is needed to coordinate actions across the system. Here's a basic implementation of the Singleton pattern in C#:

csharpCopy codepublic class Singleton
{
    private static Singleton instance;
 
    private Singleton() { }
 
    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
 
    public void SomeMethod()
    {
        Console.WriteLine("Singleton method called.");
    }
}

Usage:

csharpCopy codeSingleton.Instance.SomeMethod();

Factory Pattern

The Factory pattern is used to create objects without specifying the exact class of object that will be created. It defines an interface for creating objects, but allows subclasses to alter the type of objects that will be created. Here's a simple example of the Factory pattern:

csharpCopy codepublic interface IProduct
{
    void Operation();
}
 
public class ConcreteProductA : IProduct
{
    public void Operation()
    {
        Console.WriteLine("ConcreteProductA operation");
    }
}
 
public class ConcreteProductB : IProduct
{
    public void Operation()
    {
        Console.WriteLine("ConcreteProductB operation");
    }
}
 
public class ProductFactory
{
    public IProduct CreateProduct(string productType)
    {
        switch (productType)
        {
            case "A":
                return new ConcreteProductA();
            case "B":
                return new ConcreteProductB();
            default:
                throw new ArgumentException("Invalid product type");
        }
    }
}

Usage:

csharpCopy codeProductFactory factory = new ProductFactory();
IProduct productA = factory.CreateProduct("A");
IProduct productB = factory.CreateProduct("B");
productA.Operation();
productB.Operation();

Observer Pattern

The Observer pattern is a behavioral pattern where an object (the subject) maintains a list of its dependents (observers) and notifies them of any state changes. This pattern is commonly used in event handling systems. Here's a basic example of the Observer pattern:

csharpCopy codepublic interface IObserver
{
    void Update(string message);
}
 
public interface ISubject
{
    void Attach(IObserver observer);
    void Detach(IObserver observer);
    void Notify(string message);
}
 
public class ConcreteSubject : ISubject
{
    private List<IObserver> observers = new List<IObserver>();
 
    public void Attach(IObserver observer)
    {
        observers.Add(observer);
    }
 
    public void Detach(IObserver observer)
    {
        observers.Remove(observer);
    }
 
    public void Notify(string message)
    {
        foreach (var observer in observers)
        {
            observer.Update(message);
        }
    }
 
    public void DoSomething()
    {
        // Do something and notify observers
        Notify("Something happened");
    }
}
 
public class ConcreteObserver : IObserver
{
    public void Update(string message)
    {
        Console.WriteLine($"Received message: {message}");
    }
}

Usage:

csharpCopy codeConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observerA = new ConcreteObserver();
ConcreteObserver observerB = new ConcreteObserver();
 
subject.Attach(observerA);
subject.Attach(observerB);
 
subject.DoSomething();

In conclusion, understanding and applying design patterns in your .NET projects can lead to more maintainable, scalable, and flexible code. The Singleton, Factory, and Observer patterns are just a few examples of the many design patterns available to .NET developers, each with its own use cases and benefits. By incorporating these patterns into your designs, you can write cleaner, more efficient code that is easier to maintain and extend.

Ejan Shresthaइजन श्रेष्ठ

Senior Software Engineer, backend and .NET modernisation

Senior software engineer in Kathmandu with 4+ years shipping .NET for insurance and enterprise. I own reliability and modernisation for an insurance platform of 50 .NET projects on Kubernetes: structured logging and tracing across old and new services, the plan off end-of-life .NET to .NET 10, and the fix for socket exhaustion across ~390 call sites.

Selected impact

  • ~390Ending socket exhaustion across the platform. The error class disappeared from production logs, and outbound HTTP now has one place for retries and tracing.
  • 1 IDOne trace from gateway to database. One correlation ID now follows a request end to end.
  • 61%From end-of-life .NET to .NET 10. A sequenced roadmap with known risks; the first services already run on .NET 10.
  • v16A public website on Next.js 16. Shipped to production with a tested rollback path.
  • 4A release standard people follow. Releases are predictable enough to schedule.

Experience

  1. Senior Software Engineer, Himalayan Everest Insurance

    Jan 2025 – present

    Kathmandu, hybrid

    • Own backend reliability and modernisation for an insurance platform of 50 .NET projects, deployed as 28 Kubernetes workloads, across accounting, claims, reinsurance and reporting.
    • Leading the upgrade from .NET Core 2.2, 3.1 and 5 to .NET 10, including the IdentityServer4 replacement.
    • Built structured logging and tracing across every service.
    • Upgraded the public website and CMS to Next.js 16, React 19, Strapi 5 and Node 24.
  2. .NET Developer, EKbana Solutions

    Jul 2022 – Nov 2024

    Lalitpur, on-site

    • Designed backend services for enterprise insurance workflows with ASP.NET Core, PostgreSQL, EF Core and Dapper.
    • Built REST APIs and integrations for customer portals, payments and external partners.
    • Ran background workflows on Hangfire with idempotency, retries and failure recovery.
    • Shipped on Docker, Linux, Nginx/Traefik and Kubernetes; worked on IdentityServer, JWT and RBAC.
  3. Dotnet Developer, NBIT

    Jan 2022 – Jun 2022

    Lalitpur

    • Built and maintained .NET Framework applications for client projects.
  4. Data Specialist, CloudFactory

    Nov 2017 – Jun 2022

    Kathmandu

    • Delivered high-accuracy data work for international clients while completing my degree.