DEV Community

genichm
genichm

Posted on • Updated on

Design Patterns With Examples in C#

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);

    }
}

Enter fullscreen mode Exit fullscreen mode

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);
    }
}

Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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();
}
Enter fullscreen mode Exit fullscreen mode

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;
    }

}

Enter fullscreen mode Exit fullscreen mode

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();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Discussion (6)

Collapse
klyse profile image
klyse

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

Collapse
genichm profile image
genichm Author

Which patterns do you use often?

Collapse
klyse profile image
klyse

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

Thread Thread
genichm profile image
genichm Author

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

Thread Thread
klyse profile image
klyse

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

Thread Thread
genichm profile image
genichm Author

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