From 7296a0795063aa74b23b7555e0131f8121d0f34f Mon Sep 17 00:00:00 2001 From: Nader Mohamed Zaky Mahmoud Date: Tue, 24 Mar 2026 10:10:23 +0100 Subject: [PATCH] Add design pattern implementations and documentation - Implement Mediator Pattern with a software development team example. - Implement Observer Pattern with a weather monitoring system example. - Implement Prototype Pattern for cloning geometric figures. - Implement Proxy Pattern for lazy loading images. - Implement Singleton Pattern using a ChocolateBoiler example. - Implement State Pattern using a Gumball Machine example. - Implement Strategy Pattern with a Duck simulation example. - Implement Template Method Pattern for beverage preparation and sorting. - Implement Visitor Pattern with a housing unit example. --- AdapterPattern/README.md | 46 ++++++++ BridgePattern/README.md | 50 ++++++++ BuilderPattern/README.md | 50 ++++++++ ChainOfResponsibilityPattern/README.md | 51 ++++++++ CommandPattern/README.md | 54 +++++++++ CompositePattern/README.md | 47 ++++++++ DecoratorPattern/README.md | 45 ++++++++ FacadePattern/README.md | 47 ++++++++ FactoryPattern/README.md | 66 +++++++++++ FlyweightPattern/README.md | 94 +++++++++++++++ IteratorPattern/README.md | 96 +++++++++++++++ MediatorPattern/README.md | 94 +++++++++++++++ ObserverPattern/README.md | 118 +++++++++++++++++++ PrototypePattern/README.md | 138 ++++++++++++++++++++++ ProxyPattern/README.md | 140 ++++++++++++++++++++++ SingletonPattern/README.md | 60 ++++++++++ StatePattern/README.md | 109 +++++++++++++++++ StrategyPattern/README.md | 125 ++++++++++++++++++++ TemplatePattern/README.md | 154 +++++++++++++++++++++++++ VisitorPattern/README.md | 144 +++++++++++++++++++++++ 20 files changed, 1728 insertions(+) create mode 100644 AdapterPattern/README.md create mode 100644 BridgePattern/README.md create mode 100644 BuilderPattern/README.md create mode 100644 ChainOfResponsibilityPattern/README.md create mode 100644 CommandPattern/README.md create mode 100644 CompositePattern/README.md create mode 100644 DecoratorPattern/README.md create mode 100644 FacadePattern/README.md create mode 100644 FactoryPattern/README.md create mode 100644 FlyweightPattern/README.md create mode 100644 IteratorPattern/README.md create mode 100644 MediatorPattern/README.md create mode 100644 ObserverPattern/README.md create mode 100644 PrototypePattern/README.md create mode 100644 ProxyPattern/README.md create mode 100644 SingletonPattern/README.md create mode 100644 StatePattern/README.md create mode 100644 StrategyPattern/README.md create mode 100644 TemplatePattern/README.md create mode 100644 VisitorPattern/README.md diff --git a/AdapterPattern/README.md b/AdapterPattern/README.md new file mode 100644 index 0000000..f1401fa --- /dev/null +++ b/AdapterPattern/README.md @@ -0,0 +1,46 @@ +# Adapter Pattern + +This folder demonstrates the Adapter design pattern in C# using a turkey-to-duck adapter example. + +## Pattern overview + +Adapter lets incompatible interfaces work together. It wraps one object with another adapter so it can be used as if it implemented a target interface. + +In this example: + +- `IDuck` is the target interface used by client code. +- `ITurkey` is the adaptee interface that has a different API. +- `TurkeyAdapter` converts `ITurkey` callbacks (`Gobble`, `Fly`) into `IDuck` actions (`Quack`, `Fly`). + +## Project structure + +- `IDuck.cs`: duck contract with `Quack()` and `Fly()`. +- `ITurkey.cs`: turkey contract with `Gobble()` and `Fly()`. +- `WildTurkey.cs`: concrete turkey implementation. +- `TurkeyAdapter.cs`: adapter implementing `IDuck` by delegating to `ITurkey`. +- `Program.cs`: test harness that uses `TurkeyAdapter` where an `IDuck` is expected. + +## Behavior details + +- `TurkeyAdapter.Quack()` calls `ITurkey.Gobble()`. +- `TurkeyAdapter.Fly()` calls `ITurkey.Fly()` multiple times to compensate for turkey’s short flight capability (adaptation logic in code). + +## Usage + +```csharp +var turkey = new WildTurkey(); +var adapter = new TurkeyAdapter(turkey); +Tester(adapter); + +static void Tester(IDuck duck) +{ + duck.Fly(); + duck.Quack(); +} +``` + +## Why this pattern is useful + +- Provides compatibility between otherwise incompatible components. +- Supports reuse of existing implementations without modifying them. +- Decouples client code from concrete adaptee classes. diff --git a/BridgePattern/README.md b/BridgePattern/README.md new file mode 100644 index 0000000..c8b721d --- /dev/null +++ b/BridgePattern/README.md @@ -0,0 +1,50 @@ +# Bridge Pattern + +This folder implements the Bridge design pattern in C# illustrating how weapons and enchantments are decoupled. + +## Pattern overview + +Bridge separates an abstraction from its implementation so they can vary independently. In this example, weapons are the abstractions and enchantments are the implementations. + +- `IWeapon` is the abstraction interface. +- `IEnchantment` is the implementation interface. +- `Sword` and `Hammer` are concrete abstractions. +- `FlyingEnchantment` and `SoulEatingEnchantment` are concrete implementations. + +## How it works + +Each `IWeapon` holds an `IEnchantment`. Weapon methods delegate behavior to the enchantment, allowing any weapon to be combined with any enchantment: + +- `Wield()` calls `IEnchantment.OnActivate()` +- `Swing()` calls `IEnchantment.Apply()` +- `Unwield()` calls `IEnchantment.OnDeactivate()` + +This keeps weapon and enchantment hierarchies independent and reusable. + +## Project files + +- `IWeapon.cs`: abstraction interface. +- `IEnchantment.cs`: implementor interface. +- `Sword.cs`, `Hammer.cs`: concrete abstractions. +- `FlyingEnchantment.cs`, `SoulEatingEnchantment.cs`: concrete implementors. +- `Program.cs`: sample usage. + +## Example usage + +```csharp +IWeapon sword = new Sword(new FlyingEnchantment()); +sword.Wield(); +sword.Swing(); +sword.Unwield(); + +IWeapon hammer = new Hammer(new SoulEatingEnchantment()); +hammer.Wield(); +hammer.Swing(); +hammer.Unwield(); +``` + +## Why this pattern is useful + +- Adds flexibility by enabling combinations (weapon + enchantment) without class explosion. +- Reduces coupling and improves maintainability. +- Makes it easy to add new weapons or enchantments independently. diff --git a/BuilderPattern/README.md b/BuilderPattern/README.md new file mode 100644 index 0000000..790349d --- /dev/null +++ b/BuilderPattern/README.md @@ -0,0 +1,50 @@ +# Builder Pattern + +This folder implements the Builder design pattern in C# using hamburger construction examples. + +## Pattern overview + +Builder decouples the construction of a complex object from its representation, allowing the same construction process to create different representations. + +- `IBuilder` defines steps for building a product. +- `Hamburger` is the product being created. +- `MyHamburgerBuilder` and `WifesHamburgerBuilder` are concrete builders with different configurations. +- `Cook` acts as the director and executes build steps in a fixed order. + +## How it works + +1. `Cook` is initialized with an `IBuilder`. +2. `Cook.Build()` calls: + - `AddIngredients()` + - `AddShape()` + - `AddSize()` +3. After steps complete, `Cook` returns `builder.Build()`. +4. `Cook.ChangeBuilder()` switches builder implementations at runtime. + +## Project files + +- `IBuilder.cs`: builder interface. +- `Hamburger.cs`: product class. +- `Cook.cs`: director. +- `MyHamburgerBuilder.cs` / `WifesHamburgerBuilder.cs`: concrete builders. +- `Program.cs`: sample usage. + +## Usage + +```csharp +var builder = new MyHamburgerBuilder(); +var cook = new Cook(builder); +var myHamburger = cook.Build(); + +cook.ChangeBuilder(new WifesHamburgerBuilder()); +var wifesHamburger = cook.Build(); + +Console.WriteLine($"My Hamburger: {myHamburger}"); +Console.WriteLine($"My Wife's Hamburger: {wifesHamburger}"); +``` + +## Benefits + +- Builds different product variants with shared construction logic. +- Improves code reuse and maintainability. +- Changes to builder steps do not affect director logic. diff --git a/ChainOfResponsibilityPattern/README.md b/ChainOfResponsibilityPattern/README.md new file mode 100644 index 0000000..cd15218 --- /dev/null +++ b/ChainOfResponsibilityPattern/README.md @@ -0,0 +1,51 @@ +# Chain of Responsibility Pattern + +This folder implements the Chain of Responsibility design pattern in C# using mathematical operation handlers. + +## Pattern overview + +Chain of Responsibility allows passing requests along a chain of handlers. Each handler decides whether to process the request or pass it to the next handler in the chain. + +In this example: + +- Handlers process mathematical operations ("Add", "Minus", "Multiply"). +- Each handler checks if it can handle the operation; if not, it delegates to the next. +- If no handler can process the request, it returns null. + +## Project structure + +- `IHandler.cs`: interface with `AddChain()` and `Handle()`. +- `BaseHandler.cs`: abstract base implementing `AddChain()` and holding `_nextInLine`. +- `AdditionHandler.cs`: handles "add" by summing values. +- `SubtractionHandler.cs`: handles "minus" by subtracting values. +- `MultiplicationHandler.cs`: handles "multiply" by multiplying values. +- `Program.cs`: sets up the chain and tests operations. + +## How it works + +1. Handlers are chained: Addition → Subtraction → Multiplication. +2. `Handle()` is called on the first handler. +3. Each handler checks the `action` string. +4. If it matches, performs the operation; else, calls `_nextInLine.Handle()`. +5. Unhandled requests return null. + +## Usage + +```csharp +var additionHandler = new AdditionHandler(); +var subtractionHandler = new SubtractionHandler(); +var multiplicationHandler = new MultiplicationHandler(); + +subtractionHandler.AddChain(multiplicationHandler); +additionHandler.AddChain(subtractionHandler); + +double[] numbers = { 2, 3, 4, 5 }; +var result = additionHandler.Handle(numbers, "Add"); // 14.0 +``` + +## Why this pattern is useful + +- Decouples sender from receiver. +- Allows dynamic handler chains. +- Promotes loose coupling and extensibility. +- Easy to add new handlers without changing existing code. \ No newline at end of file diff --git a/CommandPattern/README.md b/CommandPattern/README.md new file mode 100644 index 0000000..e9d2471 --- /dev/null +++ b/CommandPattern/README.md @@ -0,0 +1,54 @@ +# Command Pattern + +This folder implements the Command design pattern in C# using a remote control example with garage doors and lights. + +## Pattern overview + +Command encapsulates a request as an object, allowing parameterization of clients with queues, requests, and operations. It also supports undoable operations. + +In this example: + +- `ICommand` defines `Execute()` and `Undo()`. +- Concrete commands (e.g., `GarageDoorOpenCommand`) encapsulate receivers and actions. +- `RemoteControl` acts as the invoker, storing and executing commands. +- `MacroCommand` composes multiple commands for batch operations. + +## Project structure + +- `ICommand.cs`: command interface. +- `RemoteControl.cs`: invoker with slots for on/off commands and undo. +- `GarageDoorOpenCommand.cs`, `GarageDoorCloseCommand.cs`: concrete commands for garage. +- `LightOnCommand.cs`, `LightOffCommand.cs`: concrete commands for light. +- `MacroCommand.cs`: composite command for multiple actions. +- `NoCommand.cs`: null object for empty slots. +- `OnOffStruct.cs`: struct for on/off command pairs. +- `Garage.cs`, `Light.cs`: receivers. +- `Program.cs`: demo usage. + +## How it works + +1. Commands are assigned to remote slots (on/off pairs). +2. `PushOn(slot)` executes the on command and sets undo to off. +3. `PushOff(slot)` executes the off command and sets undo to on. +4. `PushUndo()` executes the last command's opposite. +5. Macro commands execute multiple commands in sequence. + +## Usage + +```csharp +var remote = new RemoteControl(3); +var garage = new Garage("Bike"); +var openCmd = new GarageDoorOpenCommand(garage); +var closeCmd = new GarageDoorCloseCommand(garage); + +remote[0] = new OnOffStruct { On = openCmd, Off = closeCmd }; +remote.PushOn(0); // Opens garage +remote.PushUndo(); // Closes garage +``` + +## Why this pattern is useful + +- Decouples invoker from receiver. +- Supports undo, redo, and macro operations. +- Enables queuing and logging of requests. +- Promotes extensibility by adding new commands without changing existing code. \ No newline at end of file diff --git a/CompositePattern/README.md b/CompositePattern/README.md new file mode 100644 index 0000000..2426446 --- /dev/null +++ b/CompositePattern/README.md @@ -0,0 +1,47 @@ +# Composite Pattern + +This folder implements the Composite design pattern in C# using a restaurant menu example. + +## Pattern overview + +Composite lets clients treat individual objects and compositions of objects uniformly. It composes objects into tree structures to represent part-whole hierarchies. + +In this example: + +- `MenuComponent` is the component interface. +- `Menu` is the composite, containing child components. +- `MenuItem` is the leaf, with no children. +- Clients call `Print()` on the root menu, which recursively prints the hierarchy. + +## Project structure + +- `MenuComponent.cs`: abstract component with common interface. +- `Menu.cs`: composite that holds and manages child components. +- `MenuItem.cs`: leaf component representing individual items. +- `Program.cs`: demo building a menu hierarchy and printing it. + +## How it works + +1. `Menu` implements `Add()`, `Remove()`, `GetChild()` to manage children. +2. `MenuItem` implements leaf-specific properties (name, price, etc.). +3. `Print()` is implemented in both: + - `Menu`: prints its name, then calls `Print()` on each child. + - `MenuItem`: prints item details. +4. Clients treat menus and items uniformly via `MenuComponent`. + +## Usage + +```csharp +var menu = new Menu("All", "McDonalds"); +var breakfast = new Menu("Breakfast", "Pancake House"); +menu.Add(breakfast); +breakfast.Add(new MenuItem("Waffles", "Butterscotch waffles", 140, false)); +menu.Print(); // Prints entire hierarchy +``` + +## Why this pattern is useful + +- Simplifies client code by treating composites and leaves uniformly. +- Makes it easy to add new component types. +- Supports complex tree structures with recursive operations. +- Promotes code reuse and consistency. \ No newline at end of file diff --git a/DecoratorPattern/README.md b/DecoratorPattern/README.md new file mode 100644 index 0000000..fafa420 --- /dev/null +++ b/DecoratorPattern/README.md @@ -0,0 +1,45 @@ +# Decorator Pattern + +This folder implements the Decorator design pattern in C# using a coffee shop beverage example. + +## Pattern overview + +Decorator attaches additional responsibilities to an object dynamically. It provides a flexible alternative to subclassing for extending functionality. + +In this example: + +- `Beverage` is the component interface. +- `CondimentDecorator` is the decorator base. +- `Espresso`, `DarkRoast`, `HouseBlend` are concrete components. +- `MochaCondiment`, `WhipCondiment` are concrete decorators that wrap beverages. + +## Project structure + +- `Beverage.cs`: abstract component with `Description` and `Cost()`. +- `CondimentDecorator.cs`: abstract decorator extending `Beverage`. +- `Espresso.cs`, `DarkRoast.cs`, `HouseBlend.cs`: concrete beverages. +- `MochaCondiment.cs`, `WhipCondiment.cs`: concrete decorators adding condiments. +- `Program.cs`: demo wrapping beverages with multiple condiments. + +## How it works + +1. Decorators wrap components, delegating calls to the wrapped object. +2. Each decorator adds its own behavior (e.g., cost, description). +3. Multiple decorators can be stacked dynamically. +4. Clients treat decorated objects uniformly via the component interface. + +## Usage + +```csharp +Beverage beverage = new DarkRoast(); +beverage = new MochaCondiment(beverage); +beverage = new WhipCondiment(beverage); +Console.WriteLine(beverage.Description + " $" + beverage.Cost()); +``` + +## Why this pattern is useful + +- Adds responsibilities without subclassing. +- Combines behaviors at runtime. +- Avoids class explosion from all possible combinations. +- Follows open-closed principle for extension. \ No newline at end of file diff --git a/FacadePattern/README.md b/FacadePattern/README.md new file mode 100644 index 0000000..76e2c5c --- /dev/null +++ b/FacadePattern/README.md @@ -0,0 +1,47 @@ +# Facade Pattern + +This folder implements the Facade design pattern in C# using a home theater system example. + +## Pattern overview + +Facade provides a unified interface to a set of interfaces in a subsystem. It defines a higher-level interface that makes the subsystem easier to use. + +In this example: + +- `HomeTheatreFacade` is the facade. +- `Dimmer`, `Dvd`, `DvdPlayer` are subsystem components. +- Facade methods like `WatchMovie()` coordinate multiple subsystem calls. + +## Project structure + +- `HomeTheatreFacade.cs`: facade class with high-level methods. +- `Dimmer.cs`: subsystem for lighting control. +- `Dvd.cs`: subsystem for DVD media. +- `DvdPlayer.cs`: subsystem for DVD playback. +- `Program.cs`: demo using facade to control home theater. + +## How it works + +1. Facade holds references to subsystem objects. +2. High-level methods (e.g., `WatchMovie()`) call multiple subsystem methods in sequence. +3. Clients use the facade instead of dealing with subsystem complexity. +4. Subsystem components remain decoupled from clients. + +## Usage + +```csharp +var dimmer = new Dimmer(); +var dvdPlayer = new DvdPlayer(); +var dvd = new Dvd("Movie Title"); +var facade = new HomeTheatreFacade(dimmer, dvd, dvdPlayer); + +facade.WatchMovie(); // Coordinates dimming, turning on player, inserting DVD, playing +facade.Pause(); // Dims lights and pauses playback +``` + +## Why this pattern is useful + +- Simplifies client interaction with complex subsystems. +- Reduces coupling between clients and subsystem components. +- Promotes loose coupling and easier maintenance. +- Allows subsystem evolution without affecting clients. \ No newline at end of file diff --git a/FactoryPattern/README.md b/FactoryPattern/README.md new file mode 100644 index 0000000..74bcd22 --- /dev/null +++ b/FactoryPattern/README.md @@ -0,0 +1,66 @@ +# Factory Pattern + +This project demonstrates the implementation of two creational design patterns: the **Factory Method** pattern and the **Abstract Factory** pattern. These patterns are used together to create a pizza ordering system that can produce different styles of pizzas (New York and Chicago) with their respective ingredients. + +## Overview + +The Factory Method pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. The Abstract Factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. + +In this implementation: +- **Factory Method**: Creates different types of pizzas (Cheese, Clam, Veggie) in different styles (NY or Chicago) +- **Abstract Factory**: Creates the ingredients for each pizza style (dough, sauce, cheese, veggies, clams) + +## Project Structure + +### Core Classes +- `Pizza.cs` - Abstract base class for all pizzas with common preparation steps +- `PizzaFactory.cs` - Abstract factory method class that defines the pizza creation process +- `IIngredientsFactory.cs` - Abstract factory interface for creating pizza ingredients + +### Concrete Factories +- `NyPizzaFactory.cs` - Creates New York-style pizzas +- `ChicagoPizzaFactory.cs` - Creates Chicago-style pizzas +- `NyIngredientsFactory.cs` - Creates New York-style ingredients +- `ChicagoIngredientsFactory.cs` - Creates Chicago-style ingredients + +### Concrete Products +- `CheesePizza.cs`, `ClamPizza.cs`, `VeggiePizza.cs` - Different pizza types +- Various ingredient classes (`ThinCrust.cs`, `DeepDish.cs`, `Mozarella.cs`, `Parmesan.cs`, etc.) + +## How It Works + +1. **Pizza Ordering**: The client calls `Order()` on a concrete pizza factory (e.g., `NyPizzaFactory`) +2. **Factory Method**: The factory's `Order()` method calls the abstract `Create()` method, which is implemented by subclasses to create the appropriate pizza type +3. **Abstract Factory**: Each pizza constructor receives an `IIngredientsFactory` that creates the style-specific ingredients +4. **Preparation**: The pizza's `Prepare()` method uses the ingredients factory to get all necessary components + +### Example Usage + +```csharp +// Yankees fan orders NY-style pizza +var yankees = new NyPizzaFactory(); +yankees.Order(PizzaType.Cheese); + +// Cubs fan orders Chicago-style pizza +var cubs = new ChicagoPizzaFactory(); +cubs.Order(PizzaType.Clam); +``` + +This results in: +- NY Cheese Pizza: Thin crust, Mozarella cheese, Cherry tomato sauce, Onion/Pepper/Olive veggies +- Chicago Clam Pizza: Deep dish, Parmesan cheese, Plum tomato sauce, Onion/Cucumber/Pepper veggies, Fresh clams + +## Benefits + +1. **Encapsulation**: Object creation is encapsulated within factory classes +2. **Flexibility**: Easy to add new pizza types or ingredient families without changing existing code +3. **Consistency**: Ensures that related objects (ingredients) are created together +4. **Maintainability**: Changes to ingredient creation are isolated to their respective factories +5. **Extensibility**: New pizza styles can be added by creating new factory classes + +## Key Design Principles Demonstrated + +- **Dependency Inversion**: High-level modules (pizza factories) don't depend on low-level modules (ingredients) +- **Single Responsibility**: Each factory is responsible for creating one family of products +- **Open/Closed Principle**: New pizza types can be added without modifying existing code +c:\Repos\DesignPatterns\FactoryPattern\README.md \ No newline at end of file diff --git a/FlyweightPattern/README.md b/FlyweightPattern/README.md new file mode 100644 index 0000000..e76f667 --- /dev/null +++ b/FlyweightPattern/README.md @@ -0,0 +1,94 @@ +# Flyweight Pattern + +This project demonstrates the **Flyweight** design pattern, a structural pattern that focuses on sharing objects to support large numbers of fine-grained objects efficiently. + +## Overview + +The Flyweight pattern uses sharing to support large numbers of fine-grained objects efficiently. It separates intrinsic state (shared among all instances) from extrinsic state (unique to each instance) to minimize memory usage. + +In this implementation, a bubble tea shop uses the Flyweight pattern to share beverage objects. Instead of creating a new beverage instance for each order, the same beverage object is reused for multiple orders of the same type, significantly reducing memory consumption. + +## Project Structure + +### Core Classes +- `IBeverage.cs` - Interface defining the beverage contract +- `BeverageFlyweightFactory.cs` - Factory that manages and shares flyweight objects +- `BeverageType.cs` - Enum defining available beverage types + +### Concrete Flyweights +- `BubbleMilkTea.cs` - Bubble milk tea implementation +- `FoamMilkTea.cs` - Foam milk tea implementation +- `OolingMilkTea.cs` - Oolong milk tea implementation +- `CoconutMilkTea.cs` - Coconut milk tea implementation + +### Client Classes +- `BubbleTeaShop.cs` - Client that uses the flyweight factory to create orders +- `Program.cs` - Main entry point demonstrating the pattern + +## How It Works + +1. **Flyweight Factory**: `BeverageFlyweightFactory` maintains a dictionary cache of created beverage objects +2. **Object Creation**: When a beverage is requested, the factory checks if an instance already exists +3. **Sharing**: If the beverage type exists in cache, the cached instance is returned; otherwise, a new instance is created and cached +4. **Usage**: Multiple orders of the same beverage type share the same object instance + +### Example Output + +When running the program, you'll see initialization messages only for the first instance of each beverage type: + +``` +Initializing a Bubble Milk Tea instance +Initializing a Coconut Milk Tea instance +Initializing a Foam Milk Tea instance +Initializing an Oolong Milk Tea instance + +Enumerating take away orders + +hmmm... this is bubble milk tea +hmmm... this is bubble milk tea // Same instance reused +hmmm... this is coconut milk tea +hmmm... this is foam milk tea +hmmm... this is oolong milk tea +hmmm... this is oolong milk tea // Same instance reused +``` + +Notice that "Initializing" messages appear only once per beverage type, even though Bubble Milk Tea and Oolong Milk Tea are ordered twice each. + +## Key Components + +### Intrinsic State +- Beverage type and behavior (shared across all instances of the same type) +- Stored within the flyweight object itself + +### Extrinsic State +- Order-specific information (not implemented in this example, but would be passed to the `Drink()` method) +- Managed by client code and passed to flyweight methods as needed + +### Flyweight Factory +- Manages the pool of flyweight objects +- Ensures sharing by returning cached instances +- Creates new instances only when necessary + +## Benefits + +1. **Memory Efficiency**: Reduces memory usage by sharing objects instead of creating duplicates +2. **Performance**: Faster object creation and reduced garbage collection pressure +3. **Scalability**: Can handle large numbers of similar objects without memory issues +4. **Consistency**: Ensures all instances of the same type behave identically + +## When to Use + +- When an application uses a large number of objects +- When storage costs are high due to the sheer quantity of objects +- When most object state can be made extrinsic +- When many groups of objects can be replaced by relatively few shared objects +- When object identity is not important to the application + +## Real-World Applications + +- Text editors (sharing character objects) +- Graphics systems (sharing glyph objects) +- Game development (sharing texture/sprite objects) +- Database connection pooling +- String interning in programming languages +c:\Repos\DesignPatterns\FlyweightPattern\README.md \ No newline at end of file diff --git a/IteratorPattern/README.md b/IteratorPattern/README.md new file mode 100644 index 0000000..1459d24 --- /dev/null +++ b/IteratorPattern/README.md @@ -0,0 +1,96 @@ +# Iterator Pattern + +This project demonstrates the **Iterator** design pattern, a behavioral pattern that provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation. + +## Overview + +The Iterator pattern allows clients to traverse different types of collections (aggregates) in a uniform way, without needing to know the internal structure of the collection. It encapsulates the traversal logic within iterator objects that implement a common interface. + +In this implementation, a restaurant menu system uses the Iterator pattern to traverse breakfast and dinner menus. The menus use different data structures (ArrayList for breakfast, array for dinner), but clients can iterate over both using the same interface. + +## Project Structure + +### Core Classes +- `Menu.cs` - Represents a menu item with name, description, price, and vegetarian flag +- `IEnumerable` / `IEnumerator` - .NET interfaces for iteration (built into the framework) + +### Aggregate Classes (Collections) +- `BreakfastMenu.cs` - Stores breakfast items in an ArrayList +- `DinnerMenu.cs` - Stores dinner items in a fixed-size array + +### Iterator Classes +- `BreakfastMenuIterator.cs` - Iterator for breakfast menu (implements IEnumerable) +- `DinnerMenuIterator.cs` - Iterator for dinner menu (implements IEnumerable) + +### Enumerator Classes +- `BreakfastMenuEnum.cs` - Enumerator for breakfast menu (implements IEnumerator) +- `DinnerMenuEnum.cs` - Enumerator for dinner menu (implements IEnumerator) + +### Client Classes +- `Client.cs` - Uses the iterators to traverse and display menu items +- `Program.cs` - Main entry point demonstrating the pattern + +## How It Works + +1. **Aggregate Objects**: `BreakfastMenu` and `DinnerMenu` store menu items in different data structures +2. **Iterator Creation**: Each menu provides an `Items` property that returns an iterator implementing `IEnumerable` +3. **Traversal**: The `Client` uses `foreach` loops to iterate over the menus without knowing their internal structure +4. **Enumeration**: The iterators create enumerators that implement `IEnumerator` to handle the actual traversal + +### Key Methods +- `MoveNext()` - Advances to the next element +- `Current` - Returns the current element +- `Reset()` - Resets the iterator to the beginning + +### Example Output + +``` +Waffle Rs. 125 x + Blueberry Sauce topped breakfast Waffles +Sandwich Rs. 75 * + Veggie Sandwich with tomato and cucumber +Pankcakes Rs. 110 x + Maple syrup Pancakes +Corn Flakes Rs. 60 * + Cornflakes with fruits and nuts +Hamburger Rs. 160 x + Hamburger with cheese and onions +``` + +The `*` indicates vegetarian items, `x` indicates non-vegetarian items. + +## Benefits + +1. **Uniform Access**: Different collection types can be traversed using the same interface +2. **Encapsulation**: Internal structure of collections is hidden from clients +3. **Single Responsibility**: Iterators handle traversal logic separately from collection logic +4. **Extensibility**: New collection types can be added without changing client code +5. **Concurrent Access**: Multiple iterators can traverse the same collection simultaneously + +## Key Design Principles Demonstrated + +- **Single Responsibility Principle**: Iterators handle traversal, collections handle storage +- **Open/Closed Principle**: New iterators can be added without modifying existing code +- **Information Hiding**: Clients don't need to know collection internals + +## When to Use + +- When you need to provide a uniform way to access different types of collections +- When you want to hide the internal structure of collections from clients +- When you need to support multiple traversal algorithms for the same collection +- When you want to provide concurrent access to collections + +## Real-World Applications + +- Database result sets (different databases provide different iterator interfaces) +- File system traversal (different file systems, local vs. network) +- Collection libraries (List, Set, Map iterators in programming languages) +- UI component traversal (tree structures, composite objects) +- Streaming data processing (iterating over large datasets) + +## Comparison with Other Patterns + +- **Iterator vs. Visitor**: Iterator traverses elements, Visitor performs operations on elements +- **Iterator vs. Composite**: Iterator provides access to elements, Composite defines element hierarchies +- **Iterator vs. Observer**: Iterator provides pull-based access, Observer provides push-based notifications +c:\Repos\DesignPatterns\IteratorPattern\README.md \ No newline at end of file diff --git a/MediatorPattern/README.md b/MediatorPattern/README.md new file mode 100644 index 0000000..e642840 --- /dev/null +++ b/MediatorPattern/README.md @@ -0,0 +1,94 @@ +# Mediator Pattern + +This project demonstrates the **Mediator** design pattern, a behavioral pattern that defines how a set of objects interact with each other. Instead of objects communicating directly, they communicate through a mediator object. + +## Overview + +The Mediator pattern promotes loose coupling by keeping objects from referring to each other explicitly and lets you vary their interaction independently. It encapsulates how objects interact and makes the interaction changeable. + +In this implementation, a software development team (Customer, Programmer, Tester) communicates through a Manager mediator. Instead of team members talking directly to each other, they send messages through the manager who routes them appropriately. + +## Project Structure + +### Core Classes +- `Mediator.cs` - Abstract mediator class defining the communication contract +- `Colleague.cs` - Abstract colleague class that all participants inherit from + +### Concrete Classes +- `ManagerMediator.cs` - Concrete mediator that coordinates communication between team members +- `Customer.cs` - Represents the customer/client in the development process +- `Programmer.cs` - Represents the developer/programmer +- `Tester.cs` - Represents the quality assurance tester + +### Client Code +- `Program.cs` - Demonstrates the mediator pattern in action + +## How It Works + +1. **Mediator Setup**: A `ManagerMediator` is created and all colleagues (Customer, Programmer, Tester) are registered with it +2. **Message Sending**: When a colleague calls `Send()`, it delegates to the mediator +3. **Message Routing**: The mediator receives the message and routes it to the appropriate recipient based on the sender +4. **Message Delivery**: The target colleague's `Notify()` method is called to receive the message + +### Communication Flow + +``` +Customer → ManagerMediator → Programmer → ManagerMediator → Tester → ManagerMediator → Customer +``` + +The mediator defines the workflow: +- Customer sends message → Programmer receives it +- Programmer sends message → Tester receives it +- Tester sends message → Customer receives it + +### Example Output + +``` +Message to programmer: We have an order, need to make a program +Message to tester: I have done program, need to test it +Message to customer: I have done testing, here is ready program for you +``` + +## Benefits + +1. **Reduced Coupling**: Colleagues don't need to know about each other directly +2. **Centralized Control**: All communication logic is in one place +3. **Easy Maintenance**: Changes to communication rules only affect the mediator +4. **Extensibility**: New colleagues can be added without changing existing code +5. **Reusability**: Colleagues can be reused with different mediators + +## Key Design Principles Demonstrated + +- **Single Responsibility**: Each colleague focuses on its own work, mediator handles communication +- **Open/Closed Principle**: New colleagues can be added without modifying existing ones +- **Dependency Inversion**: Colleagues depend on the mediator abstraction, not concrete implementations + +## When to Use + +- When objects communicate in complex but well-defined ways +- When reusing objects is difficult due to tight coupling +- When behavior distributed among several classes should be customizable +- When you want to centralize complex communications and control logic + +## Real-World Applications + +- **Air Traffic Control**: Planes communicate through control tower instead of directly +- **Chat Applications**: Users send messages through chat server/room +- **GUI Dialog Boxes**: UI components communicate through dialog controller +- **Workflow Systems**: Tasks communicate through workflow engine +- **Event Buses**: Components publish/subscribe through central event bus + +## Comparison with Other Patterns + +- **Mediator vs. Observer**: Mediator centralizes communication logic, Observer distributes it +- **Mediator vs. Facade**: Facade simplifies interface, Mediator manages object interactions +- **Mediator vs. Command**: Command encapsulates requests, Mediator routes them + +## Implementation Notes + +This implementation shows a simple mediator that routes messages in a linear workflow. In real applications, mediators can be more complex with: +- Multiple recipients for a single message +- Conditional routing based on message content +- Asynchronous communication +- Message queuing and persistence +c:\Repos\DesignPatterns\MediatorPattern\README.md \ No newline at end of file diff --git a/ObserverPattern/README.md b/ObserverPattern/README.md new file mode 100644 index 0000000..d2b8c22 --- /dev/null +++ b/ObserverPattern/README.md @@ -0,0 +1,118 @@ +# Observer Pattern + +This project demonstrates the **Observer** design pattern, a behavioral pattern that defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. + +## Overview + +The Observer pattern allows objects to subscribe to events and get notified when the state of another object changes. It establishes a relationship where the subject maintains a list of observers and notifies them of any state changes. + +In this implementation, a weather monitoring system uses the Observer pattern. Weather monitors subscribe to a weather supplier and receive notifications when weather conditions change, displaying relevant data based on their monitoring focus. + +## Project Structure + +### Core Classes +- `IObservable` / `IObserver` - .NET interfaces for the observer pattern +- `Weather.cs` - Data class representing weather conditions (temperature, humidity, pressure) + +### Subject (Observable) +- `WeatherSupplier.cs` - The subject that maintains weather data and notifies observers + +### Observers +- `WeatherMonitor.cs` - Concrete observer that displays weather information +- `Unsubscriber.cs` - Helper class for managing observer unsubscriptions + +### Client +- `Program.cs` - Demonstrates the observer pattern in action + +## How It Works + +1. **Subscription**: Observers call `Subscribe()` on the weather supplier to register for notifications +2. **State Change**: When `WeatherConditions()` is called on the supplier, it creates a new Weather object +3. **Notification**: The supplier iterates through all registered observers and calls `OnNext()` on each +4. **Update**: Each observer receives the weather data and displays relevant information based on its configuration + +### Observer Types + +The implementation includes different types of weather monitors: +- **TP Monitor**: Displays Temperature and Pressure data +- **H Monitor**: Displays Humidity data + +### Example Output + +``` +TP +| Temperature : 32 Celsius || Pressure : 1.5 atm | +TP +| Temperature : 33.5 Celsius || Pressure : 1.7 atm | +H +| Humidity : 4 % | +TP +| Temperature : 37.5 Celsius || Pressure : 1.2 atm | +H +| Humidity : 7 % | +``` + +## Key Components + +### Subject (WeatherSupplier) +- Maintains a list of observers +- Provides `Subscribe()` method for observers to register +- Implements `WeatherConditions()` to update state and notify observers +- Returns `Unsubscriber` object for clean unsubscription + +### Observer (WeatherMonitor) +- Implements `IObserver` interface +- Provides `OnNext()`, `OnError()`, `OnCompleted()` methods +- Displays weather data based on monitor type (TP, H) +- Can unsubscribe using the returned `IDisposable` + +### Weather Data +- Immutable data class with temperature, humidity, and pressure +- Passed to observers when state changes + +## Benefits + +1. **Loose Coupling**: Subject and observers are loosely coupled - subject doesn't need to know concrete observer classes +2. **Dynamic Relationships**: Observers can be added or removed at runtime +3. **Broadcast Communication**: Changes are automatically broadcast to all interested observers +4. **Extensibility**: New observer types can be added without modifying the subject +5. **Separation of Concerns**: Subject focuses on its domain logic, observers handle their own display logic + +## Key Design Principles Demonstrated + +- **Open/Closed Principle**: New observers can be added without changing existing code +- **Single Responsibility**: Each class has a single, well-defined responsibility +- **Dependency Inversion**: High-level modules don't depend on low-level modules + +## When to Use + +- When changes to one object require changing others, and you don't know how many objects need to be changed +- When an object should be able to notify other objects without making assumptions about who these objects are +- When you need to maintain consistency between related objects +- When you want to broadcast information to multiple receivers + +## Real-World Applications + +- **GUI Systems**: UI components subscribe to model changes +- **News/Magazine Subscriptions**: Readers subscribe to publications +- **Stock Market**: Investors subscribe to stock price changes +- **Social Media**: Followers subscribe to account updates +- **Event Systems**: Event listeners subscribe to event sources +- **Model-View Patterns**: Views subscribe to model changes + +## Comparison with Other Patterns + +- **Observer vs. Mediator**: Observer distributes communication, Mediator centralizes it +- **Observer vs. Publish-Subscribe**: Observer is a specific implementation of publish-subscribe +- **Observer vs. Command**: Observer reacts to state changes, Command encapsulates requests + +## Implementation Notes + +This implementation uses .NET's built-in `IObservable` and `IObserver` interfaces, which provide: +- Type safety through generics +- Standard contract for observer pattern implementation +- Built-in support for error handling and completion +- Automatic unsubscription management + +The pattern demonstrates both push and pull models - the subject pushes weather data to observers, and observers pull specific data they need based on their configuration. +c:\Repos\DesignPatterns\ObserverPattern\README.md \ No newline at end of file diff --git a/PrototypePattern/README.md b/PrototypePattern/README.md new file mode 100644 index 0000000..88b110a --- /dev/null +++ b/PrototypePattern/README.md @@ -0,0 +1,138 @@ +# Prototype Pattern + +This project demonstrates the **Prototype** design pattern, a creational pattern that allows cloning objects without coupling to their specific classes. + +## Overview + +The Prototype pattern specifies the kinds of objects to create using a prototypical instance, and creates new objects by copying this prototype. It allows you to create new instances by copying existing objects, which can be more efficient than creating objects from scratch. + +In this implementation, geometric figures (Rectangle and Circle) can be cloned to create new instances with the same properties, demonstrating how the Prototype pattern enables object duplication. + +## Project Structure + +### Core Classes +- `IFigure.cs` - Interface extending `ICloneable` that defines the contract for clonable figures +- `ICloneable` - .NET interface providing the `Clone()` method + +### Concrete Prototypes +- `Rectangle.cs` - Rectangle figure that can be cloned +- `Circle.cs` - Circle figure that can be cloned + +### Client +- `Program.cs` - Demonstrates cloning figures using the prototype pattern + +## How It Works + +1. **Prototype Definition**: Classes implement `ICloneable` interface with a `Clone()` method +2. **Cloning**: When `Clone()` is called, the object creates a copy of itself +3. **Client Usage**: Client code can create new objects by cloning existing prototypes +4. **Independence**: Cloned objects are independent of their prototypes + +### Example Usage + +```csharp +// Create original rectangle +IFigure figure = new Rectangle(30, 40); + +// Clone it to create a new instance +IFigure clonedFigure = (IFigure)figure.Clone(); + +// Both have the same properties but are different objects +figure.GetInfo(); // "Rectangle height 40 and width 30" +clonedFigure.GetInfo(); // "Rectangle height 40 and width 30" +``` + +### Example Output + +``` +Rectangle height 40 and width 30 +Rectangle height 40 and width 30 +Circle with radius 30 +Circle with radius 30 +``` + +## Key Components + +### Prototype Interface +- Defines the contract for clonable objects +- Extends .NET's `ICloneable` interface +- Requires implementation of `Clone()` method + +### Concrete Prototypes +- Implement the prototype interface +- Provide their own cloning logic +- Can have complex initialization that gets copied + +### Client +- Uses prototypes to create new objects +- Doesn't need to know concrete classes +- Works with cloned objects as independent instances + +## Benefits + +1. **Reduced Subclassing**: Avoids creating subclasses for different object configurations +2. **Runtime Flexibility**: Add/remove prototypes at runtime +3. **Performance**: Cloning can be more efficient than complex construction +4. **Encapsulation**: Hides complex object creation logic +5. **Consistency**: Ensures cloned objects have same initial state + +## Key Design Principles Demonstrated + +- **Single Responsibility**: Each prototype handles its own cloning +- **Open/Closed Principle**: New prototypes can be added without changing existing code +- **Dependency Inversion**: Client depends on abstractions, not concrete classes + +## When to Use + +- When object creation is expensive or complex +- When you want to avoid subclasses for different configurations +- When you need to create objects at runtime with varying properties +- When you want to hide the complexity of object creation +- When the system needs to be independent of how its products are created + +## Real-World Applications + +- **Graphic Editors**: Clone shapes, brushes, or effects +- **Game Development**: Clone characters, weapons, or game objects +- **Document Systems**: Clone documents, pages, or templates +- **Configuration Objects**: Clone settings or preferences +- **Database Records**: Clone data objects for modification +- **UI Components**: Clone widgets or controls + +## Implementation Considerations + +### Shallow vs Deep Copy +- This implementation uses shallow copying (copying primitive values) +- For complex objects with references, deep copying may be needed +- Consider using serialization for deep cloning + +### Prototype Registry +- For complex systems, maintain a registry of available prototypes +- Allows clients to specify prototypes by name or key +- Enables dynamic prototype management + +### Clone Method Variations +- MemberwiseClone() for shallow copying +- Custom logic for selective copying +- Serialization/deserialization for deep copying + +## Comparison with Other Patterns + +- **Prototype vs. Factory**: Factory creates objects from scratch, Prototype clones existing objects +- **Prototype vs. Builder**: Builder constructs complex objects step-by-step, Prototype copies complete objects +- **Prototype vs. Singleton**: Singleton ensures one instance, Prototype allows multiple copies + +## .NET Implementation Notes + +This implementation uses .NET's `ICloneable` interface, which: +- Provides a standard way to implement cloning +- Returns `object` type (requires casting) +- Doesn't specify shallow vs. deep copying +- Is considered legacy; consider custom interfaces for new code + +For modern .NET development, consider: +- Custom clone interfaces with generic return types +- Record types with built-in cloning +- Serialization-based deep cloning +- Immutable objects that don't need cloning +c:\Repos\DesignPatterns\PrototypePattern\README.md \ No newline at end of file diff --git a/ProxyPattern/README.md b/ProxyPattern/README.md new file mode 100644 index 0000000..9e349dd --- /dev/null +++ b/ProxyPattern/README.md @@ -0,0 +1,140 @@ +# Proxy Pattern + +This project demonstrates the **Proxy** design pattern, a structural pattern that provides a surrogate or placeholder for another object to control access to it. + +## Overview + +The Proxy pattern provides 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. + +In this implementation, a proxy image provides lazy loading for real images. Instead of loading images from disk immediately when created, the proxy delays loading until the image is actually displayed, improving performance and memory usage. + +## Project Structure + +### Core Classes +- `Image.cs` - Interface defining the contract for image objects + +### Real Subject +- `RealImage.cs` - The actual image implementation that loads from disk + +### Proxy +- `ProxyImage.cs` - Virtual proxy that controls access to RealImage with lazy loading + +### Client +- `Program.cs` - Demonstrates the proxy pattern usage + +## How It Works + +1. **Proxy Creation**: Client creates a `ProxyImage` instead of `RealImage` +2. **Lazy Loading**: Proxy stores the filename but doesn't load the image yet +3. **First Access**: When `display()` is called, proxy creates the `RealImage` and loads it +4. **Subsequent Access**: Proxy delegates to the already loaded `RealImage` + +### Example Usage + +```csharp +// Create proxy - image not loaded yet +Image image = new ProxyImage("testImage.jpg"); + +// First display - image gets loaded from disk +image.display(); // "Loading testImage.jpg" then "Displaying testImage.jpg" + +// Second display - image already loaded, no disk access +image.display(); // "Displaying testImage.jpg" (no loading message) +``` + +### Example Output + +``` +Loading testImage.jpg +Displaying testImage.jpg + +Displaying testImage.jpg +``` + +Notice that "Loading" only appears once, demonstrating the lazy loading behavior. + +## Types of Proxies + +### Virtual Proxy (Implemented) +- Delays creation of expensive objects until needed +- Used for lazy loading and performance optimization + +### Protection Proxy +- Controls access to sensitive objects +- Adds security checks before allowing operations + +### Remote Proxy +- Represents objects in different address spaces +- Handles network communication transparently + +### Smart Proxy +- Performs additional actions when accessing objects +- Reference counting, logging, caching + +## Benefits + +1. **Performance**: Delays expensive operations until necessary +2. **Memory Efficiency**: Creates heavy objects only when needed +3. **Access Control**: Can add security and validation layers +4. **Transparency**: Client code works with proxy as if it were the real object +5. **Remote Access**: Enables distributed object communication + +## Key Design Principles Demonstrated + +- **Single Responsibility**: Proxy handles access control, real object handles functionality +- **Open/Closed Principle**: New proxy types can be added without changing existing code +- **Dependency Inversion**: Client depends on abstraction (Image interface) + +## When to Use + +- When object creation is expensive and should be deferred +- When you need to control access to sensitive objects +- When objects are in remote locations (distributed systems) +- When you need to add logging, caching, or other cross-cutting concerns +- When you want to postpone resource-intensive operations + +## Real-World Applications + +- **Image Loading**: Virtual proxies for images, videos, documents +- **Database Connections**: Connection pooling and lazy initialization +- **Web Services**: Remote proxies for service calls +- **Security**: Protection proxies for access control +- **Caching**: Smart proxies that cache results +- **Logging**: Proxies that log method calls +- **ORM**: Lazy loading of related objects + +## Implementation Considerations + +### Proxy vs. Decorator +- **Proxy**: Controls access to the same interface +- **Decorator**: Adds behavior to the same interface +- Both implement the same interface as the wrapped object + +### Proxy vs. Adapter +- **Proxy**: Represents the same object with access control +- **Adapter**: Converts one interface to another +- Proxy maintains the same interface, adapter changes it + +### Thread Safety +- Virtual proxies may need synchronization for multi-threaded access +- Consider using double-checked locking for thread-safe lazy initialization + +## Comparison with Other Patterns + +- **Proxy vs. Adapter**: Proxy provides same interface with access control, Adapter changes interface +- **Proxy vs. Decorator**: Proxy controls access, Decorator adds functionality +- **Proxy vs. Facade**: Proxy controls single object access, Facade simplifies subsystem interfaces +- **Proxy vs. Flyweight**: Proxy controls access to one object, Flyweight shares multiple objects + +## .NET Implementation Notes + +This implementation uses: +- Interface-based design for loose coupling +- Lazy initialization pattern in the proxy +- Standard .NET naming conventions + +For more advanced scenarios, consider: +- `Lazy` for thread-safe lazy initialization +- Dynamic proxies using `RealProxy` or third-party libraries +- Aspect-oriented programming for cross-cutting concerns +c:\Repos\DesignPatterns\ProxyPattern\README.md \ No newline at end of file diff --git a/SingletonPattern/README.md b/SingletonPattern/README.md new file mode 100644 index 0000000..d91dc55 --- /dev/null +++ b/SingletonPattern/README.md @@ -0,0 +1,60 @@ +# Singleton Pattern + +This folder implements the Singleton design pattern in C# using a `ChocolateBoiler` example. + +## Pattern overview + +Singleton ensures a class has only one instance and provides a global point of access to it. + +Key characteristics: + +- single instance is created +- controlled access through a static method +- private constructor prevents external instantiation +- thread-safe lazy initialization using `Lazy` + +## Implementation details + +- `ChocolateBoiler` class is the singleton. +- The instance is stored in a private static field: + - `private static readonly Lazy _singleton` +- Access is through: + - `public static ChocolateBoiler GetInstance()` +- Constructor is private: + - `private ChocolateBoiler()` + +State machine: + +- `Status.Empty` +- `Status.InProgress` +- `Status.Boiled` + +Methods enforce state transition rules: + +- `Fill()` → from Empty to InProgress +- `Boil()` → from InProgress to Boiled +- `Drain()` → from Boiled to Empty + +## Usage + +In `Program.Main()`: + +```csharp +var chocoEggs = ChocolateBoiler.GetInstance(); +chocoEggs.Fill(); +chocoEggs.Boil(); +chocoEggs.Drain(); +``` + +The same instance is returned on subsequent `GetInstance()` calls. + +## Why use Singleton? + +- ensures consistent object state across the app +- avoids repeated expensive initialization +- useful for shared services or resources (config, logger, connection pools) + +## Notes + +- In multithreaded contexts, `Lazy` makes initialization thread-safe by default. +- Avoid overuse, as Singleton can introduce hidden global state and tight coupling. diff --git a/StatePattern/README.md b/StatePattern/README.md new file mode 100644 index 0000000..3781f5d --- /dev/null +++ b/StatePattern/README.md @@ -0,0 +1,109 @@ +# State Pattern + +## Overview + +The **State Pattern** is a behavioral design pattern that allows an object to alter its behavior when its internal state changes. The object will appear to change its class. This pattern is particularly useful when an object's behavior depends on its state, and it must change its behavior at runtime depending on that state. + +## Project Structure + +This project demonstrates the State Pattern using a Gumball Machine example. The project contains: + +- `GumballMachine.cs` - The context class that maintains a reference to the current state +- `IState.cs` - The state interface defining the contract for all concrete states +- `NoQuarterState.cs` - State when no quarter is inserted +- `HasQuarterState.cs` - State when a quarter is inserted +- `SoldState.cs` - State when the crank is turned and gumball is being dispensed +- `SoldOutState.cs` - State when the machine is out of gumballs +- `WinnerState.cs` - Special state for when the user wins an extra gumball +- `Program.cs` - Main program demonstrating the pattern usage +- `Legacy/` - Contains the legacy implementation using conditional statements for comparison + +## How It Works + +### Context (GumballMachine) +The `GumballMachine` class acts as the context. It: +- Maintains a reference to the current state (`IState State`) +- Defines all possible states as properties +- Delegates state-specific behavior to the current state object +- Provides methods that clients call (`InsertQuarter()`, `EjectQuarter()`, `TurnCrank()`) + +### State Interface (IState) +The `IState` interface defines the contract that all concrete states must implement: +- `InsertQuarter()` - Handle quarter insertion +- `EjectQuarter()` - Handle quarter ejection +- `TurnCrank()` - Handle crank turning +- `Dispense()` - Handle gumball dispensing + +### Concrete States +Each concrete state implements the `IState` interface and encapsulates the behavior for that specific state: + +- **NoQuarterState**: Accepts quarter insertion, rejects other actions +- **HasQuarterState**: Accepts crank turning or quarter ejection, includes winner logic +- **SoldState**: Dispenses gumball and transitions to appropriate next state +- **SoldOutState**: Rejects all actions when machine is empty +- **WinnerState**: Dispenses two gumballs for the price of one + +## Example Usage + +```csharp +// Create a gumball machine with 5 gumballs +var gumballMachine = new GumballMachine(5); + +// Insert quarter and turn crank +gumballMachine.InsertQuarter(); // "Inserted a quarter" +gumballMachine.TurnCrank(); // "You turned the crank" + "A ball comes rolling down" + +// Try invalid operations +gumballMachine.TurnCrank(); // "Can't turn crank without a quarter" +gumballMachine.EjectQuarter(); // "Can't eject anything" +``` + +## Benefits + +1. **Single Responsibility**: Each state class has a single responsibility - handling behavior for one state +2. **Open/Closed Principle**: Easy to add new states without modifying existing code +3. **Eliminates Conditional Complexity**: Replaces large switch/if-else statements with polymorphism +4. **State Transitions**: Clear and explicit state transitions +5. **Maintainability**: Changes to state behavior are localized to the specific state class + +## When to Use + +- When an object's behavior depends on its state and it must change behavior at runtime +- When operations have large, multipart conditional statements that depend on the object's state +- When you have many conditional branches that are difficult to maintain +- When state-specific behavior is complex and varies significantly between states + +## Real-World Applications + +- **Vending Machines**: Different behaviors based on inventory and payment state +- **Network Connections**: Connected, connecting, disconnected states with different behaviors +- **Document States**: Draft, review, published states with different editing permissions +- **Game Character States**: Idle, walking, running, jumping states +- **Order Processing**: Pending, processing, shipped, delivered states +- **Media Players**: Playing, paused, stopped states with different control behaviors + +## Comparison with Legacy Implementation + +The `Legacy` folder contains an implementation using conditional statements instead of the State pattern. Compare the differences: + +**State Pattern Benefits:** +- Cleaner code with no large switch statements +- Easy to add new states (just create new class) +- State-specific behavior is encapsulated +- Better testability of individual states + +**Legacy Drawbacks:** +- Large conditional blocks that are hard to maintain +- Adding new states requires modifying existing code +- Mixed concerns in a single class +- Harder to test individual state behaviors + +## Implementation Considerations + +- Define a clear state interface that all states implement +- The context should delegate state-specific behavior to the current state +- States can have references back to the context for state transitions +- Consider using the State pattern when you have more than 2-3 states +- States should be immutable where possible +- Consider thread-safety if states can be accessed concurrently +c:\Repos\DesignPatterns\StatePattern\README.md \ No newline at end of file diff --git a/StrategyPattern/README.md b/StrategyPattern/README.md new file mode 100644 index 0000000..04635f6 --- /dev/null +++ b/StrategyPattern/README.md @@ -0,0 +1,125 @@ +# Strategy Pattern + +## Overview + +The **Strategy Pattern** is a behavioral design pattern that defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it. This pattern is particularly useful when you have multiple ways to perform the same task and want to be able to switch between them dynamically. + +## Project Structure + +This project demonstrates the Strategy Pattern using a Duck simulation example. The project contains: + +- `Duck.cs` - The context class that maintains references to strategy objects +- `MallardDuck.cs` - A concrete duck implementation +- `IFlyBehaviour.cs` - Strategy interface for flying behavior +- `FlyWings.cs` - Concrete strategy for flying with wings +- `FlyNope.cs` - Concrete strategy for ducks that can't fly +- `IQuackBehaviour.cs` - Strategy interface for quacking behavior +- `QuackNormal.cs` - Concrete strategy for normal quacking +- `QuackNope.cs` - Concrete strategy for silent ducks +- `QuackSqueak.cs` - Concrete strategy for squeaking ducks +- `Program.cs` - Main program demonstrating the pattern usage + +## How It Works + +### Context (Duck) +The `Duck` class acts as the context. It: +- Maintains references to strategy objects (`IFlyBehaviour` and `IQuackBehaviour`) +- Provides setters to change strategies at runtime +- Delegates behavior execution to the current strategy objects +- Defines `PerformFly()` and `PerformQuack()` methods that call the strategies + +### Strategy Interfaces +- `IFlyBehaviour` - Defines the contract for flying algorithms +- `IQuackBehaviour` - Defines the contract for quacking algorithms + +### Concrete Strategies +Each concrete strategy implements one of the strategy interfaces: + +**Fly Behaviors:** +- `FlyWings` - Implements flying by flapping wings +- `FlyNope` - Implements inability to fly + +**Quack Behaviors:** +- `QuackNormal` - Implements standard duck quacking +- `QuackNope` - Implements silence (no quacking) +- `QuackSqueak` - Implements squeaking instead of quacking + +### Concrete Context (MallardDuck) +`MallardDuck` extends `Duck` and: +- Sets default behaviors in its constructor +- Can have its behaviors changed dynamically at runtime +- Calls `PerformFly()` and `PerformQuack()` to execute current strategies + +## Example Usage + +```csharp +// Create a mallard duck with default behaviors +var mallard = new MallardDuck(); + +// Change quack behavior at runtime +mallard.Quacker = new QuackNormal(); + +// Display current behavior +mallard.Display(); // Output: "I can't fly" + "Quack Quack" + +// Change fly behavior at runtime +mallard.Flyer = new FlyWings(); + +// Display new behavior +mallard.Display(); // Output: "Flap Flap" + "Quack Quack" +``` + +## Benefits + +1. **Open/Closed Principle**: New strategies can be added without modifying existing code +2. **Composition over Inheritance**: Behaviors are composed rather than inherited +3. **Runtime Flexibility**: Strategies can be changed dynamically +4. **Single Responsibility**: Each strategy class has one responsibility +5. **Testability**: Individual strategies can be tested in isolation +6. **Eliminates Conditional Logic**: No need for switch statements or if-else chains + +## When to Use + +- When you have multiple algorithms for the same task and want to switch between them dynamically +- When you want to avoid exposing complex, algorithm-specific data structures +- When a class has many conditional statements that switch between different behaviors +- When you need different variants of an algorithm (e.g., different sorting algorithms) +- When you want to isolate algorithm implementation from the code that uses it + +## Real-World Applications + +- **Payment Processing**: Different payment strategies (credit card, PayPal, bank transfer) +- **Sorting Algorithms**: QuickSort, MergeSort, BubbleSort strategies +- **Compression Algorithms**: ZIP, RAR, GZIP compression strategies +- **Authentication**: Different authentication methods (password, OAuth, biometric) +- **Navigation**: Different routing algorithms (fastest, shortest, scenic routes) +- **Logging**: Different logging strategies (console, file, database, remote server) +- **Image Processing**: Different filter strategies (blur, sharpen, edge detection) +- **Data Validation**: Different validation strategies (strict, lenient, custom rules) + +## Implementation Considerations + +- Define a clear strategy interface that all concrete strategies implement +- The context should work with strategies through the interface, not concrete classes +- Consider making strategies stateless if possible (no instance variables) +- Strategies should be interchangeable - clients shouldn't know the difference +- Consider using the Strategy pattern when you have more than 2-3 algorithm variants +- For simple cases with few algorithms, inheritance might be simpler +- Strategies can be shared across different contexts if they're stateless + +## Comparison with Other Patterns + +**Strategy vs State:** +- Strategy: Client chooses algorithm explicitly +- State: Object changes behavior based on internal state + +**Strategy vs Template Method:** +- Strategy: Composition-based, algorithms can be changed at runtime +- Template Method: Inheritance-based, algorithm structure is fixed + +**Strategy vs Command:** +- Strategy: Defines how something is done +- Command: Defines what to do and when + +This implementation demonstrates how the Strategy pattern enables flexible, maintainable code by separating algorithms from the objects that use them. +c:\Repos\DesignPatterns\StrategyPattern\README.md \ No newline at end of file diff --git a/TemplatePattern/README.md b/TemplatePattern/README.md new file mode 100644 index 0000000..654d903 --- /dev/null +++ b/TemplatePattern/README.md @@ -0,0 +1,154 @@ +# Template Method Pattern + +## Overview + +The **Template Method Pattern** is a behavioral design pattern that defines the skeleton of an algorithm in a method, deferring some steps to subclasses. It lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure. This pattern is particularly useful when you have a multi-step algorithm where some steps are fixed while others vary. + +## Project Structure + +This project demonstrates the Template Method Pattern using two examples: + +- **Beverage Preparation**: Abstract `Beverage` class with template method for preparing hot beverages +- **Sorting**: `Person` class implementing `IComparable` for custom sorting logic + +### Beverage Classes +- `Beverage.cs` - Abstract base class defining the template method `Prepare()` +- `Coffee.cs` - Concrete class implementing coffee-specific brewing and condiment steps +- `Tea.cs` - Concrete class implementing tea-specific brewing and condiment steps + +### Comparable Classes +- `Person.cs` - Implements `IComparable` interface for custom sorting by name and age + +- `Program.cs` - Main program demonstrating both template method examples + +## How It Works + +### Beverage Template Method +The `Beverage` abstract class defines the `Prepare()` template method that outlines the algorithm: + +```csharp +public void Prepare() +{ + Boil(); // Fixed step + Brew(); // Abstract step - implemented by subclasses + Pour(); // Fixed step + if (WantsCondiments) + AddCondiments(); // Abstract step - implemented by subclasses +} +``` + +**Abstract Steps (Implemented by Subclasses):** +- `Brew()` - How to brew the beverage (coffee grounds vs tea leaves) +- `AddCondiments()` - What condiments to add (milk/sugar vs lemon/sugar) + +**Concrete Steps (Fixed in Base Class):** +- `Boil()` - Always boils water +- `Pour()` - Always pours into cup + +### IComparable Template Method +The `Person` class implements `IComparable.CompareTo()` which serves as a template method: + +```csharp +public int CompareTo(object obj) +{ + var other = (Person)obj; + if (String.Compare(Name, other.Name, StringComparison.Ordinal) == 0) + { + return Age.CompareTo(other.Age); // Secondary sort by age + } + return String.Compare(Name, other.Name, StringComparison.Ordinal); // Primary sort by name +} +``` + +## Example Usage + +### Beverage Preparation +```csharp +// Prepare tea with condiments +var tea = new Tea(); +tea.WantsCondiments = true; +tea.AddSugar = 5; +tea.Prepare(); +// Output: +// Boling Water +// Adding tea leaves to water and boil +// Pouring in Cup +// Adding Lemon and Sugar +// adding 5 spoons of sugar + +// Prepare coffee with condiments +var coffee = new Coffee(); +coffee.WantsCondiments = true; +coffee.Prepare(); +// Output: +// Boling Water +// Add Coffee Grounds to water and boil +// Pouring in Cup +// Add Milk and Sugar +``` + +### Custom Sorting +```csharp +var people = new List { + new Person("Ram", 25), + new Person("Abishek", 12), + new Person("Ram", 18), + new Person("Abishek", 18) +}; + +// Before sorting: Ram:25, Abishek:12, Ram:18, Abishek:18 +people.Sort(); +// After sorting: Abishek:12, Abishek:18, Ram:18, Ram:25 (name first, then age) +``` + +## Benefits + +1. **Code Reuse**: Common algorithm structure is defined once in the base class +2. **Inversion of Control**: Base class controls the algorithm flow, subclasses provide specific implementations +3. **Consistency**: Ensures all subclasses follow the same algorithm structure +4. **Extensibility**: Easy to add new variations by creating new subclasses +5. **Maintainability**: Changes to the algorithm structure only need to be made in one place + +## When to Use + +- When you have an algorithm with invariant parts that should be in a base class +- When you want to allow subclasses to redefine certain steps of an algorithm +- When you have common behavior among subclasses that can be factored into a common base class +- When you want to control the points of extension in an algorithm +- When implementing frameworks or libraries where users need to customize specific steps + +## Real-World Applications + +- **Framework Development**: Base framework classes with customizable hooks +- **Data Processing Pipelines**: ETL processes with customizable transformation steps +- **UI Frameworks**: Window creation with customizable initialization steps +- **Game Development**: Character creation with customizable ability assignment +- **Document Processing**: File parsing with customizable validation and processing steps +- **Authentication Flows**: Login process with customizable credential validation +- **Build Systems**: Compilation process with customizable pre/post build steps +- **Sorting and Comparison**: Custom comparison logic for different data types + +## Implementation Considerations + +- **Hook Methods**: Consider providing hook methods (like `WantsCondiments`) that subclasses can override to customize behavior +- **Abstract vs Virtual**: Use abstract methods for required customizations, virtual methods for optional ones +- **Template Method Naming**: Template methods are usually final (not overridable) to preserve algorithm structure +- **Primitive Operations**: The varying steps are called "primitive operations" or "hook operations" +- **Hollywood Principle**: "Don't call us, we'll call you" - base class controls when to call subclass methods + +## Comparison with Other Patterns + +**Template Method vs Strategy:** +- Template Method: Inheritance-based, algorithm structure is fixed +- Strategy: Composition-based, entire algorithm can be swapped + +**Template Method vs Factory Method:** +- Template Method: Defines algorithm skeleton with varying steps +- Factory Method: Creates objects, often used within template methods + +**Template Method vs Command:** +- Template Method: Defines how a multi-step process works +- Command: Encapsulates a single action or request + +This implementation demonstrates how the Template Method pattern provides a powerful way to define algorithm skeletons while allowing customization through inheritance. +c:\Repos\DesignPatterns\TemplatePattern\README.md \ No newline at end of file diff --git a/VisitorPattern/README.md b/VisitorPattern/README.md new file mode 100644 index 0000000..b39617b --- /dev/null +++ b/VisitorPattern/README.md @@ -0,0 +1,144 @@ +# Visitor Pattern + +## Overview + +The **Visitor Pattern** is a behavioral design pattern that lets you define a new operation without changing the classes of the elements on which it operates. This pattern allows you to separate algorithms from the objects on which they operate, making it easy to add new operations without modifying existing code. + +## Project Structure + +This project demonstrates the Visitor Pattern using a housing unit example. The project contains: + +- `Unit.cs` - Abstract base class for all housing units (composite structure) +- `Apartment.cs` - Concrete apartment element +- `Studio.cs` - Concrete studio element +- `Bedroom.cs` - Concrete bedroom element +- `LivingRoom.cs` - Concrete living room element +- `IUnitVisitor.cs` - Visitor interface defining operations for each element type +- `ApartmentVisitor.cs` - Concrete visitor that operates on apartments +- `StudioVisitor.cs` - Concrete visitor that operates on studios +- `BedroomVisitor.cs` - Concrete visitor that operates on bedrooms +- `LivingRoomVisitor.cs` - Concrete visitor that operates on living rooms +- `Program.cs` - Main program demonstrating the pattern usage + +## How It Works + +### Element Hierarchy (Unit Classes) +The `Unit` abstract class represents elements in a composite structure: + +```csharp +public abstract class Unit +{ + public virtual void Accept(IUnitVisitor visitor) + { + // Visit child units recursively + foreach (var unit in _units) + { + unit.Accept(visitor); + } + } +} +``` + +**Concrete Elements:** +- `Apartment` - Contains multiple rooms, calls `visitor.VisitApartment(this)` +- `Studio` - Contains rooms, calls `visitor.VisitStudio(this)` +- `Bedroom` - Leaf element, calls `visitor.VisitBedroom(this)` +- `LivingRoom` - Leaf element, calls `visitor.VisitLivingRoom(this)` + +### Visitor Interface +`IUnitVisitor` defines the contract that all concrete visitors must implement: + +```csharp +public interface IUnitVisitor +{ + void VisitApartment(Apartment apartment); + void VisitStudio(Studio studio); + void VisitBedroom(Bedroom bedroom); + void VisitLivingRoom(LivingRoom livingRoom); +} +``` + +### Concrete Visitors +Each concrete visitor implements operations for specific element types: + +- **ApartmentVisitor**: Only responds to apartments (`VisitApartment`) +- **StudioVisitor**: Only responds to studios (`VisitStudio`) +- **BedroomVisitor**: Only responds to bedrooms (`VisitBedroom`) +- **LivingRoomVisitor**: Only responds to living rooms (`VisitLivingRoom`) + +## Example Usage + +```csharp +// Create housing units +var apartment = new Apartment(new LivingRoom(), new Bedroom(), new Bedroom()); +var studio = new Studio(new LivingRoom(), new Bedroom()); + +// Visit apartment with different visitors +Console.WriteLine("Visiting an Apartment"); +apartment.Accept(new ApartmentVisitor()); // "This is an apartment" +apartment.Accept(new LivingRoomVisitor()); // "This is the living room" +apartment.Accept(new BedroomVisitor()); // "Here is a bedroom" (twice) + +// Visit studio with different visitors +Console.WriteLine("Visiting a Studio"); +studio.Accept(new StudioVisitor()); // "This is a studio" +studio.Accept(new LivingRoomVisitor()); // "This is the living room" +studio.Accept(new BedroomVisitor()); // "Here is a bedroom" +``` + +## Benefits + +1. **Open/Closed Principle**: Easy to add new operations without modifying element classes +2. **Single Responsibility**: Each visitor encapsulates one operation +3. **Separation of Concerns**: Algorithms are separated from object structure +4. **Extensibility**: New visitors can be added without changing existing code +5. **Double Dispatch**: Correct method called based on both visitor and element types +6. **Clean Interfaces**: Element classes don't need to know about all possible operations + +## When to Use + +- When you have a complex object structure and need to perform operations on elements +- When you need to add new operations to existing classes without modifying them +- When operations depend on the concrete types of objects in a structure +- When you want to avoid polluting element classes with operation-specific code +- When you have operations that require access to private members of elements +- When the object structure rarely changes but operations are added frequently + +## Real-World Applications + +- **Document Processing**: Different visitors for rendering (HTML, PDF, XML), validation, or analysis +- **Abstract Syntax Trees**: Compiler operations like type checking, code generation, optimization +- **GUI Frameworks**: Different visitors for layout, rendering, event handling +- **File System Operations**: Visitors for file compression, encryption, backup +- **Database Operations**: Visitors for query optimization, schema validation, migration +- **Shopping Cart**: Visitors for tax calculation, discount application, inventory checking +- **Game Development**: Visitors for AI behavior, physics simulation, rendering +- **XML/HTML Processing**: Visitors for parsing, validation, transformation +- **Report Generation**: Visitors for different report formats (PDF, Excel, CSV) + +## Implementation Considerations + +- **Double Dispatch**: The pattern relies on method overloading to achieve double dispatch +- **Visitor Interface**: Must have a method for each concrete element type +- **Element Modification**: Elements must accept visitors and call the appropriate visit method +- **Circular Dependencies**: Visitors depend on element classes, elements depend on visitor interface +- **Adding Elements**: Requires updating all existing visitors when new element types are added +- **Composite Pattern**: Often used together with Composite pattern for tree structures +- **Performance**: Method dispatch overhead, but usually acceptable + +## Comparison with Other Patterns + +**Visitor vs Strategy:** +- Visitor: Defines operations on elements without changing them +- Strategy: Allows interchangeable algorithms for a single operation + +**Visitor vs Command:** +- Visitor: Defines what to do with each element type +- Command: Encapsulates a single action or request + +**Visitor vs Iterator:** +- Visitor: Performs operations on elements during traversal +- Iterator: Provides access to elements without exposing structure + +This implementation demonstrates how the Visitor pattern enables clean separation of algorithms from data structures, making systems more maintainable and extensible. +c:\Repos\DesignPatterns\VisitorPattern\README.md \ No newline at end of file