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.
- Private constructor https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/private-constructors
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();
}
}
}
Top comments (6)
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...