loading...

Design Patterns With Examples in C#

genichm profile image genichm Updated on ・2 min read

A list of design patterns with examples in C#
[Observer, Adapter, Facade, Singleton, Factory Method, Bridge]

Behavioral patterns

Observer

Allows objects to notify other objects about changes in their state (publisher and subscribers). More information with the example available here https://docs.microsoft.com/en-us/dotnet/standard/events/observer-design-pattern


interface IObserver{
    void Update(object update);
}

interface ISubject{
    void Attach(IObserver observer);
    void Detach(IObserver observer);
    void Notify();
}

class Subject: ISubject{
    private List<IObserver> _subjectObservers;

    public Subject(){
        _subjectObservers = new List<IObserver>();
    }

    void Attach(IObserver observer){
        _subjectObservers.Add(observer);
    }

    void Detach(IObserver observer){
        _subjectObservers.Remove(observer);
    }

    void Notify(){
        foreach(var observer in _subjectObservers){
            observer.Update("Some state");
        }
    }

    /*
        Some logic that calls to Notify when needed
    */
}

class ObserverA: IObserver{
    void Update(object update){

    }
}

class ObserverB: IObserver{
    void Update(object update){

    }
}

class SomeClass{
    public void Init(){
        var observerA = new ObserverA();
        var observerB = new ObserverB();
        var subject = new Subject();
        subject.Attach(observerA);

    }
}


Structural patterns

Adapter

Allows incompatible interfaces to work together


class ToAdapt{
    public int Calculate(int a, int b){
        return a * b;
    }
}

class IAdaptInterface{
     public void CalculateWithLessParameters(int a);
}

class Adapter: ToAdapt, IAdaptInterface{
    public int CalculateWithLessParameters(int a){
        return Calculate(a, 10);
    }
}

Facade

Provides a simplified interface to complex classes, libraries

public class MemoryCacheFacade
{
    private MemoryCache _memoryCache;

    public MemoryCacheFacade(MemoryCacheOptions memoryCacheOptions)
    {
        _memoryCache = new MemoryCache(memoryCacheOptions);
    }

    public void Set<TItem>(object key, TItem value)
    {
        _memoryCache.Set(key, value);
    }

    public bool TryGetValue<TItem>(object key, out TItem result)
    {
        if (_memoryCache.TryGetValue(key, out result)) 
        {
            return true;
        }

        return false;
    }

    public ICacheEntry CreateEntry(object key)
    {
            return _memoryCache.CreateEntry(key);
    }
}

Bridge

Bridge design pattern decouples implementation from an abstraction. Useful in versioning when a new software replaces the old but both should run together for the existing codebase.


class Abstraction{
    Bridge _bridge;
    public Abstraction(Bridge bridge){
        _bridge = bridge;
    }

    public string Execute(){
        _bridge.ExecuteSomeFunction();
    }
}

interface IBridge{
    void ExecuteSomeFunction();
}

class Version1: IBridge{
    public void ExecuteSomeFunction(){

    }
}

class Version2: IBridge{
    public void ExecuteSomeFunction(){

    }
}

static void Main(){
    (new Abstraction(new Version1())).Execute();
    (new Abstraction(new Version2())).Execute();
}

Creational patterns

Singleton

Design pattern ensures that only one object of its type exists and there is an access point to that object.


class Singleton{

    private static Singleton singeltonInstance=null;

    /*
        Private constructor here is to prevent creation of
        multiple instances of this class
    */
    private Singleton()  
    {  
    } 

    public static Singleton SingletonInstance{
        if(singeltonInstance == null){
            singeltonInstance = new Singleton();
        }
        return singeltonInstance;
    }

}


Factory Method

Provides an interface for creating objects without specifying their concrete classes.

interface IShip{
    string Name();
}

class BigShip: IShip{
    public string Name(){
        return "Big ship";
    }
}

class SmallShip: IShip{
    public string Name(){
         return "Small ship";
    }
}

class Creator{
    private bool _bigShipAvailable = true;
    public IShip FactoryMethod(){
        if(_bigShipAvailable){
            _bigShipAvailable  = false;
            return new BigShip();
        }else{
            return new SmallShip();
        }
    }
}

Posted on by:

genichm profile

genichm

@genichm

Software Architect and Tech Lead in IoT industry

Discussion

pic
Editor guide
 

This actually reminded me of some patterns I'm not using that often :)

 

Which patterns do you use often?

 

I think CQRS is a very good pattern to follow, that for sure I'm using often :)

Do you have some example of using CQRS? It can be interesting :)

I usually use this nuget: github.com/jbogard/MediatR/wiki and follow some implementation/design pattern I find in the Internet.
This one is great IMHO:
youtu.be/dK4Yb6-LxAk

Created post based on your comment, will add mediator design pattern to the list too.
dev.to/genichm/cqrs-command-and-qu...