Skip to content

Commit e470ca5

Browse files
docs(readme): update README with new sections and improvements
1 parent 3a4a68f commit e470ca5

1 file changed

Lines changed: 73 additions & 1 deletion

File tree

README.md

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,22 @@ This repository showcases .NET C# Design Patterns. The patterns can be browsed b
99
## Contents
1010
- [What Are Design Patterns?](#what-are-design-patterns)
1111
- [GoF Design Patterns](#gof-design-patterns)
12+
- [Quickstart](#quickstart)
1213
- [Categories of Design Patterns](#categories-of-design-patterns)
1314
- [Creational Patterns](#creational-patterns)
1415
- [Structural Patterns](#structural-patterns)
1516
- [Behavioral Patterns](#behavioral-patterns)
1617
- [Importance of Design Patterns](#importance-of-design-patterns)
1718
- [Why Use Design Patterns?](#why-use-design-patterns)
19+
- [Overview Table of GoF Patterns](#overview-table-of-gof-patterns)
1820
- [Patterns vs. Anti-patterns](#patterns-vs-anti-patterns)
21+
- [When to Use or Avoid Each Pattern](#when-to-use-or-avoid-each-pattern)
1922
- [.NET and Design Patterns](#net-and-design-patterns)
23+
- [.NET Mapping Cheatsheet](#net-mapping-cheatsheet)
2024
- [Repository Layout](#repository-layout)
21-
- [How to Contribute](#how-to-contribute)
2225
- [Examples and Use Cases](#examples-and-use-cases)
26+
- [How to Contribute](#how-to-contribute)
27+
- [Further Reading](#further-reading)
2328
- [License](#license)
2429
- [Contact](#contact)
2530

@@ -77,6 +82,34 @@ Patterns offer ways to handle changing requirements and evolving designs by deco
7782
## Why Use Design Patterns?
7883
Design patterns act as a toolbox of proven solutions, helping developers create better, more efficient, and maintainable software. They offer a structured approach to problem-solving, improve code readability, and facilitate collaboration among team members.
7984

85+
## Overview Table of GoF Patterns
86+
87+
| Pattern | Category | Description |
88+
|---------|----------|-------------|
89+
| **Abstract Factory** | Creational | Provide an interface for creating families of related or dependent objects without specifying their concrete classes. |
90+
| **Builder** | Creational | Separate the construction of a complex object from its representation so that the same process can create different representations. |
91+
| **Factory Method** | Creational | Define an interface for object creation, but let subclasses decide which class to instantiate. |
92+
| **Prototype** | Creational | Create new objects by copying an existing object (prototype) rather than creating from scratch. |
93+
| **Singleton** | Creational | Ensure a class has only one instance, and provide a global point of access to it. |
94+
| **Adapter** | Structural | Allow incompatible interfaces to work together by wrapping one with an adapter. |
95+
| **Bridge** | Structural | Decouple an abstraction from its implementation so the two can vary independently. |
96+
| **Composite** | Structural | Compose objects into tree structures to represent part-whole hierarchies; clients treat individual objects and compositions uniformly. |
97+
| **Decorator** | Structural | Attach additional responsibilities to objects dynamically. |
98+
| **Facade** | Structural | Provide a unified interface to a set of interfaces in a subsystem. |
99+
| **Flyweight** | Structural | Use sharing to support large numbers of fine-grained objects efficiently. |
100+
| **Proxy** | Structural | Provide a surrogate or placeholder for another object to control access or defer costly operations. |
101+
| **Chain of Responsibility** | Behavioral | Allow a request to be passed along a chain of handlers until one handles it. |
102+
| **Command** | Behavioral | Encapsulate a request as an object, thereby letting you parameterize clients with queues, requests, and operations. |
103+
| **Interpreter** | Behavioral | Define a representation for a grammar of a language, and an interpreter to deal with this grammar. |
104+
| **Iterator** | Behavioral | Provide a way to access elements of an aggregate object sequentially without exposing its underlying representation. |
105+
| **Mediator** | Behavioral | Define an object that encapsulates how a set of objects interact. |
106+
| **Memento** | Behavioral | Capture and externalize an object’s internal state so that it can be restored later, without breaking encapsulation. |
107+
| **Observer** | Behavioral | Define a one-to-many dependency so that when one object changes state, all its dependents are notified. |
108+
| **State** | Behavioral | Allow an object to alter its behavior when its internal state changes; object appears to change class. |
109+
| **Strategy** | Behavioral | Define a family of algorithms, encapsulate each one, and make them interchangeable. |
110+
| **Template Method** | Behavioral | Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. |
111+
| **Visitor** | Behavioral | Represent an operation to be performed on elements of an object structure without changing the classes of the elements. |
112+
80113
## Patterns vs. Anti-patterns
81114
Design patterns and anti-patterns play crucial roles in software development, each representing opposing approaches to solving programming challenges:
82115
- **Design Patterns**:
@@ -94,10 +127,49 @@ Design patterns and anti-patterns play crucial roles in software development, ea
94127
- Poor understanding and ineffective communication among team members.
95128
- Spread of poor design practices, causing numerous bugs and making new code integration challenging.
96129

130+
## When to Use or Avoid Each Pattern
131+
| Pattern | When to Use | When to Avoid |
132+
|---------|-------------|---------------|
133+
| **Abstract Factory** | When you need to create families of related objects without depending on concrete classes. | If you only need a few objects and don’t need family consistency. |
134+
| **Builder** | When constructing a complex object step by step with different representations. | If the object is simple and doesn’t need stepwise construction. |
135+
| **Factory Method** | When subclasses should decide which concrete class to instantiate. | If you don’t need flexibility in instantiation. |
136+
| **Prototype** | When creating new objects by cloning existing ones is cheaper than creating from scratch. | If objects are simple or cloning is more expensive than direct creation. |
137+
| **Singleton** | When exactly one instance must exist and be globally accessible. | If global state leads to hidden dependencies or testing becomes hard. |
138+
| **Adapter** | When you need to make incompatible interfaces work together. | If you can refactor the code to use a common interface instead. |
139+
| **Bridge** | When you want to decouple abstraction from implementation so both can vary. | If the hierarchy is stable and won’t evolve separately. |
140+
| **Composite** | When working with tree structures (part-whole hierarchies) and want uniform access. | If the structure is flat and simple, no hierarchy needed. |
141+
| **Decorator** | When you want to add behavior dynamically without modifying classes. | If object composition makes debugging/maintenance too complex. |
142+
| **Facade** | When you want to simplify a complex subsystem with a unified interface. | If a simple wrapper hides too much functionality needed by clients. |
143+
| **Flyweight** | When you need to handle many similar objects efficiently by sharing state. | If objects are unique and sharing state gives no benefit. |
144+
| **Proxy** | When you want a placeholder to control access (e.g., lazy load, security). | If indirection adds unnecessary complexity or overhead. |
145+
| **Chain of Responsibility** | When multiple handlers can process a request without hardcoding sender–receiver. | If request flow must be predictable and explicit. |
146+
| **Command** | When you need to encapsulate requests, support undo/redo, or queue/log actions. | If direct method calls are simpler and sufficient. |
147+
| **Interpreter** | When you have a grammar to interpret and it’s relatively simple. | If grammar is complex — use a parser/DSL instead. |
148+
| **Iterator** | When you want sequential access to elements without exposing structure. | If simple loops over collections are enough. |
149+
| **Mediator** | When you want to centralize and simplify complex communications between objects. | If communication is simple and a mediator adds indirection. |
150+
| **Memento** | When you need to save and restore object state without exposing internals. | If state saving is too costly in memory or performance. |
151+
| **Observer** | When you want one-to-many notifications of state changes. | If frequent updates cause performance issues or cascading changes. |
152+
| **State** | When an object’s behavior should change based on internal state. | If state changes are rare or can be handled with conditionals. |
153+
| **Strategy** | When you need interchangeable algorithms encapsulated behind a common interface. | If only one algorithm exists and will not change. |
154+
| **Template Method** | When you want to define the skeleton of an algorithm but let subclasses fill steps. | If subclassing leads to rigid inheritance and reduced flexibility. |
155+
| **Visitor** | When you need to perform operations on object structures without modifying them. | If the object structure changes often — adding visitors becomes painful. |
156+
97157
## .NET and Design Patterns
98158
The .NET platform, especially with C#, offers rich language features (like delegates, LINQ, async/await, and dependency injection) that make many design patterns more expressive and efficient to implement. Patterns like Dependency Injection, Singleton, Factory, and Observer are commonly used in .NET-based enterprise solutions and are well-supported by frameworks like ASP.NET Core and libraries like `Microsoft.Extensions.*`
99159
In this repository, each pattern is demonstrated using idiomatic C# to reflect best practices in the .NET ecosystem.
100160

161+
## .NET Mapping Cheatsheet
162+
- **Singleton**`IServiceCollection.AddSingleton<T>()`, `Lazy<T>`
163+
- **Strategy** → Interfaces + DI, runtime selection via factory/Keyed services
164+
- **Observer**`IObservable<T>/IObserver<T>`, C# events, `IChangeToken`
165+
- **Decorator** → Multiple registrations / `Scrutor` (service decoration)
166+
- **Adapter** → Wrapper for external SDKs (e.g., HTTP client), `HttpMessageHandler`
167+
- **Factory Method / Abstract Factory**`IServiceProvider`, factory delegate `Func<T>`
168+
- **Command** → MediatR, `IRequestHandler<>`
169+
- **Iterator**`IEnumerable<T>`, `yield return`
170+
- **Template Method** → Base classes + `virtual` methods
171+
- **Proxy**`HttpClient` / generated clients, dynamic proxies (Castle, DispatchProxy)
172+
101173
## Repository Layout
102174
Each design pattern category has its own directory and each pattern inside has its own folder, its description and its source code.
103175

0 commit comments

Comments
 (0)