Home

Awesome

<h1 align="center">Design Patterns Library</h1> <p align="center"> 33 Design Patterns • 73 moderately realistic examples </p>

What are Design Patterns?

In software engineering, a design pattern is a general repeatable solution to a commonly occurring problem in software design. A design pattern isn't a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations. In addition, design patterns allow developers to communicate using well-known, well understood names for software interactions.

Know when to use a certain design pattern, and when not to. No design pattern is a 42 - the answer to life, the universe and everything. There are situations in which every design pattern easily becomes an antipattern.

Design Pattern Types

Design patterns can be separated into three main categories:

Creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation.

Structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships among entities. Structural patterns are concerned with how classes and objects are composed to form larger structures.

Behavioral patterns are concerned with algorithms and the assignment of responsibilities between objects. Behavioral patterns describe not just the patterns of objects or classes but also the patterns of communication between them.

What this repository contains?

This repository contains a comprehensive design patterns library implemented in C#, which covers various design patterns from the most commonly used ones (Gang of Four) to the lesser-known ones. It enables you to get familiar with and learn design patterns through moderately realistic examples.

Design PatternTypeDescriptionIntroduction
Abstract FactoryCreationalProvides an interface for creating families of related or dependent objects without specifying their concrete classes.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
AdapterStructuralAllows objects with incompatible interfaces to collaborate.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
BridgeStructuralLets you split a large class or a set of closely related classes into two separate hierarchies—abstraction and implementation—which can be developed independently of each other.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
BuilderCreationalLets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
Chain Of ResponsibilityBehavioralLets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
CommandBehavioralTurns a request into a stand-alone object that contains all information about the request. This transformation lets you parameterize methods with different requests, delay or queue a request’s execution, and support undoable operations.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
CompositeStructuralLets you compose objects into tree structures and then work with these structures as if they were individual objects. Treat individual objects and compositions of objects uniformly.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
DecoratorStructuralLets you attach new behaviors to objects by placing these objects inside special wrapper objects that contain the behaviors. Extend or alter the functionality of objects at runtime.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
FacadeStructuralProvides a simplified interface to a library, a framework, or any other complex set of classes. This makes a complex body of code simpler to use and consume.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
Factory MethodCreationalProvides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
FlyweightStructuralLets you fit more objects into the available amount of RAM by sharing common parts of state between multiple objects instead of keeping all of the data in each object. It reduces storage costs for a large number of objects.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
IteratorBehavioralLets you traverse elements of a collection without exposing its underlying representation (list, stack, tree, etc.)<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
MediatorBehavioralLets you reduce chaotic dependencies between objects. The pattern restricts direct communications between the objects and forces them to collaborate only via a mediator object.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
MementoBehavioralLets you save and restore the previous state of an object without revealing the details of its implementation.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
ObserverBehavioralLets you define a subscription mechanism to notify multiple objects about any events that happen to the object they are observing.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
PrototypeCreationalLets you copy existing objects without making your code dependent on their classes.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
ProxyStructuralLets you provide a substitute or placeholder for another object. A proxy controls access to the original object, allowing you to perform something either before or after the request gets through to the original object.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
SingletonCreationalEnsures that a class has only one instance, while providing a global access point to this instance.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
StateBehavioralLets an object alter its behavior when its internal state changes. It appears as if the object changed its class. This pattern is close to the concept of finite-state machines.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
StrategyBehavioralEnables an algorithm’s behavior to be selected at runtime. The pattern defines a family of algorithms, encapsulates each algorithm and makes the algorithms interchangeable within that family. In other words, this pattern is used when we have multiple algorithms for a specific task and we want the client to decide which actual implementation should be used at runtime.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
Template MethodBehavioralDefines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">
VisitorBehavioralA way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures.<img src="https://github.com/nemanjarogic/DesignPatternsLibrary/blob/main/assets/images/twitter.png" height="16" width="20">

Extra content

Design PatternTypeDescription
Event AggregatorBehavioralChannel events from multiple objects into a single object to simplify registration for clients.
Fluent InterfaceCreationalProvides an easy-readable, flowing interface, that often mimics a domain specific language. Using this pattern results in code that can be read nearly as human language.
InterpreterBehavioralDefines a grammatical representation for a language and provides an interpreter to evaluate sentences in a language.
Lazy LoadData AccessDefers initialization of an object until the point at which it is needed. It can contribute to efficiency in the program's operation if properly and appropriately used.
Null ObjectBehavioralEncapsulates the absence of an object by providing a substitutable alternative that offers suitable default do nothing behavior.
RepositoryData AccessEncapsulates all the minutiae of data access. Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
RulesBehavioralSeparates the logic of each individual rule and its effects into its own class. Separates the selection and processing of rules into a separate Evaluator class.
Service LocatorArchitecturalImproves the modularity of your application by removing the dependency between the client and the implementation of an interface. Encapsulates the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the service locator which on request returns the information necessary to perform a certain task.
SpecificationArchitecturalSeparates the statement of how to match a candidate, from the candidate object that it is matched against. Specification design pattern allows us to check whether our objects meet certain requirements. Through this design pattern, we can reuse expression specifications and combine those specifications to easily question whether more complex requirements are satisfied or not.
Unit Of WorkData AccessMaintains a list of objects affected by a business transaction and coordinates the writing out of changes.

How to run

The solution contains one executable project called DesignPatternsLibrary.
Run the solution and you will get a menu from which you can choose a design pattern.

<img src="assets/images/console-menu.png" width="600"/>

Compare the output from the console with the code for the chosen design pattern.
Repeat!

The solution can be run using either .NET 5 (choose .NET 5 branch or release) or .NET 6 (the default option).

Afterword

For learning more about design patterns, I highly recommend:

The examples that are used to demonstrate design patterns usage are a mix of my own ideas and ideas adapted from various resources (some of them are mentioned above).