SWD392 - Design Patterns - ManhNC5
SWD392 - Design Patterns - ManhNC5
2. Builder: Separates the construction of a complex object from its representation so that
the same construction process can create different representations. This pattern enables
the step-by-step creation of complex objects, offering flexibility in constructing various
representations.
3. Factory Method: Defines an interface for creating objects, but lets subclasses decide
which class to instantiate. This pattern delegates object creation to subclasses, providing
flexibility in choosing the type of object to be created.
4. Prototype: Specifies the kinds of objects to create using a prototypical instance, which is
cloned to produce new objects. This pattern allows for the creation of new objects by
copying existing objects, avoiding expensive initialization or complex setup.
5. Singleton: Ensures that a class has only one instance and provides a global point of
access to it. This pattern ensures the existence of only one instance of a class and
provides a global access point to that instance.
1.2. Structural Patterns: These patterns are concerned with how classes and
objects are composed to form larger structures.
6. Adapter: Converts the interface of a class into another interface clients expect. This
pattern lets classes with incompatible interfaces work together, allowing for code reuse
without modifying existing code.
7. Bridge: Decouples an abstraction from its implementation so that the two can vary
independently. This pattern separates the abstraction from its implementation, allowing
for independent variations and flexibility.
10. Facade: Provides a simplified interface to a complex subsystem. This pattern hides the
complexities of a subsystem behind a simpler interface, making it easier to use and
understand.
11. Flyweight: Shares objects to support large numbers of fine-grained objects efficiently.
This pattern minimizes memory usage by sharing common state among multiple objects,
especially beneficial for large numbers of similar objects.
12. Proxy: Provides a surrogate or placeholder for another object to control access to it. This
pattern controls access to an object, offering benefits like lazy initialization, caching, or
security checks.
1.3. Behavioral Patterns: These patterns are concerned with the assignment of
responsibilities between objects and how they communicate.
13. Chain of Responsibility: Avoids coupling the sender of a request to its receiver by
giving multiple objects a chance to handle the request. This pattern decoupled the sender
and receiver of a request, enabling multiple objects to potentially handle it.
14. Command: Encapsulates a request as an object, thereby letting you parameterize clients
with different requests, queue or log requests, and support undoable operations. This
pattern represents a request as an object, facilitating parameterization, queuing, logging,
and undo/redo functionalities.
15. Interpreter: Given a language, defines a representation for its grammar along with an
interpreter that uses the representation to interpret sentences in the language. This pattern
defines a grammatical representation for a language and provides an interpreter to process
it, commonly used for parsing expressions and queries.
16. Iterator: Provides a way to access the elements of an aggregate object sequentially
without exposing its underlying representation. This pattern allows for sequential access
to elements of an aggregate object without exposing its internal structure, offering a
consistent iteration method.
17. Mediator: Defines an object that encapsulates how a set of objects interact. This pattern
reduces dependencies between objects by introducing a mediator to manage their
communication, promoting loose coupling.
18. Memento: Without violating encapsulation, captures and externalizes an object's internal
state so that the object can be restored to this state later. This pattern saves and restores an
object's internal state without exposing its structure, facilitating undo/redo functionalities
and state persistence.
19. Observer: Defines a one-to-many dependency between objects so that when one object
changes state, all its dependents are notified and updated automatically. This pattern
notifies multiple objects (observers) about changes in a subject object, promoting loose
coupling and flexible event handling.
20. State: Allows an object to alter its behavior when its internal state changes. This pattern
encapsulates different states of an object as separate classes, enabling smooth transitions
between states.
21. Strategy: Defines a family of algorithms, encapsulates each one, and makes them
interchangeable. This pattern allows for dynamic selection and use of different algorithms
at runtime, promoting flexibility and extensibility.
22. Template Method: Defines the skeleton of an algorithm in an operation, deferring some
steps to subclasses. This pattern defines the overall structure of an algorithm in a base
class, permitting subclasses to override specific steps, promoting code reuse and
consistency.
1. Abstract Factory
Purpose: Provides an interface for creating families of related or dependent objects without
specifying their concrete classes.
What it is: A creational pattern that allows you to produce families of products (objects) without
having to specify their concrete classes, promoting flexibility and maintainability.
Benefits:
o When you need to create families of related objects without knowing their concrete
classes in advance.
o When you want to enforce consistency in object creation across the application.
1. Define an abstract factory interface with methods for creating each product type.
2. Create concrete factory classes that implement the abstract factory interface, each responsible for
creating a specific family of products.
3. The client code uses the abstract factory interface to create objects, unaware of the concrete
factory being used.
Real-world example: Creating different UI elements (buttons, text boxes, etc.) for different
operating systems (Windows, macOS, Linux) using a single abstract factory.
C# Code Example:
IButton CreateButton();
ITextBox CreateTextBox();
}
// Concrete Factory for macOS
// Product interfaces
void Render();
void Render();
}
// Concrete product classes (Windows)
}
public class MacTextBox : ITextBox
// Client code
button.Render();
textBox.Render();
}
private static IGUIFactory GetFactoryForOS()
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
else
Explanation: This example demonstrates how an Abstract Factory (IGUIFactory) is used to create
different UI elements based on the operating system. The client code only interacts with the abstract
factory and product interfaces, making it independent of the concrete classes.
2. Builder
Purpose: Separates the construction of a complex object from its representation so that the same
construction process can create different representations.
What it is: A creational pattern that enables the step-by-step creation of complex objects, offering
flexibility in constructing various representations.
Benefits:
o Allows for the creation of different variations of an object using the same builder.
o When the construction of an object involves multiple steps and potential variations.
o When you want to hide the internal representation of the object from the client.
2. Create concrete builder classes that implement the builder interface, each responsible for building
a specific variation of the object.
3. Create a director class that coordinates the building process by calling the builder methods in a
specific order.
4. The client code uses the director and a concrete builder to construct the desired object.
Real-world example: Building a house with various configurations (number of floors, types of
rooms, materials, etc.) using a single builder.
C# Code Example:
// Product class
// Builder interface
void Reset();
House GetHouse();
}
public void BuildFloors(int floors)
_house.Floors = floors;
return _house;
_house.Floors = floors;
return _house;
}
}
// Director class
public void Construct(IHouseBuilder builder, int floors, string walls, string roof)
builder.Reset();
builder.BuildFloors(floors);
builder.BuildWalls(walls);
builder.BuildRoof(roof);
// Client code
Console.WriteLine(woodenHouse);
Console.WriteLine(brickHouse);
Explanation: This example demonstrates how the Builder pattern allows for different variations of a
House to be built using the same director and different builders. The director orchestrates the construction
process, and the concrete builders define the specific details of each variation.
3. Factory Method
Purpose: Defines an interface for creating objects, but lets subclasses decide which class to
instantiate.
What it is: A creational pattern that delegates object creation to subclasses, providing flexibility
in choosing the type of object to be created.
Benefits:
o Decouples the client code from concrete product classes, allowing for new product types
to be added without modifying client code.
o When you want to allow subclasses to control the type of objects created.
o When you want to decouple the client code from concrete product classes, making it
easier to add new product types later.
How to use it:
1. Define a creator class with an abstract factory method that returns an object of a product type.
2. Create concrete creator subclasses that implement the factory method, each returning a specific
type of product.
3. The client code uses the creator class to create objects, unaware of the concrete creator being
used.
Real-world example: Creating different types of documents (PDF, Word, Text) using a factory
method that delegates the creation to specific document creator classes.
C# Code Example:
// Product interface
void Open();
void Save();
{
Console.WriteLine("Saving PDF document...");
document.Open();
document.Save();
}
// Client code
Explanation: This example shows how the DocumentCreator class defines an abstract CreateDocument
method, which is implemented by concrete creator subclasses (PDFCreator and WordCreator) to return
specific document types.
4. Prototype
Purpose: Specifies the kinds of objects to create using a prototypical instance, which is cloned to
produce new objects.
What it is: A creational pattern that allows for the creation of new objects by copying existing
objects (prototypes), avoiding expensive initialization or complex setup.
Benefits:
o Provides a way to create new objects without knowing their concrete classes.
o When the cost of creating a new object is high and you need multiple instances with
similar configurations.
2. Create concrete prototype classes that implement the prototype interface and override the Clone
method to create a copy of themselves.
3. The client code uses the prototype object to create new objects by calling the Clone method.
Real-world example: Creating new game characters by cloning a prototype character object,
allowing for different attributes and abilities.
C# Code Example:
// Prototype interface
IPrototype Clone();
Name = name;
Health = health;
Attack = attack;
// Shallow copy
return (IPrototype)this.MemberwiseClone();
// Client code
monster1.Name = "Orc";
monster2.Health = 150;
Explanation: This example shows how a Monster prototype can be cloned to create new monsters with
similar initial characteristics. The client code can then modify the properties of the cloned monsters as
needed.
5. Singleton
Purpose: Ensures that a class has only one instance and provides a global point of access to it.
What it is: A creational pattern that restricts the instantiation of a class to a single instance and
provides a global access point to that instance.
Benefits:
o When you need a single, globally accessible instance of a class (e.g., a logger, database
connection, configuration manager).
o When you need to control access to a shared resource.
3. Provide a static method (usually called GetInstance) that returns the single instance. This method
should create the instance if it doesn't exist and return the existing instance if it does.
Real-world example: Creating a logger class that has only one instance, allowing all parts of the
application to log messages to the same file.
C# Code Example:
private Logger()
if (_instance == null)
lock (padlock)
{
if (_instance == null)
return _instance;
Console.WriteLine($"Log: {message}");
// Client code
Explanation: The Logger class has a private constructor and a static GetInstance method that returns the
single instance of the logger. The lock statement ensures that only one instance is created even in multi-
threaded environments.
6. Adapter
Purpose: Converts the interface of a class into another interface clients expect.
What it is: A structural pattern that acts as a bridge between two incompatible interfaces. It
allows classes with incompatible interfaces to work together by wrapping the "adaptee" and
providing a target interface.
Benefits:
o Promotes code reusability by enabling the use of existing classes with incompatible
interfaces.
o Improves flexibility by decoupling the client code from the concrete implementation of
the adaptee.
o When you want to use an existing class, but its interface doesn't match the interface
required by the client.
o When you want to create a reusable component that can be adapted to work with different
classes.
2. Create an adapter class that implements the target interface and contains an instance of the
adaptee.
3. Implement the target interface methods in the adapter, delegating the calls to the appropriate
methods of the adaptee.
Real-world example: Imagine you have a legacy system that uses an old data format. You want
to integrate it with a new system that uses a different format. An adapter can be used to bridge the
gap between the two systems, allowing them to exchange data seamlessly.
C# Code Example:
}
// Adapter
_legacySystem = legacySystem;
_legacySystem.Pay(amountInCents);
// Client code
Explanation: This example shows how the LegacyPaymentAdapter class adapts the
LegacyPaymentSystem (adaptee) to the IModernPaymentGateway (target) interface, enabling the client to
use the legacy system seamlessly.
7. Bridge
Purpose: Decouples an abstraction from its implementation so that the two can vary
independently.
What it is: A structural pattern that separates an abstraction from its implementation, allowing
them to vary independently. This promotes flexibility by providing a bridge between the
abstraction and the implementation.
Benefits:
o When you want to avoid a permanent binding between an abstraction and its
implementation.
Real-world example: Imagine you have a remote control (abstraction) that can control different
devices (implementations) like TV, DVD player, and Music System. The bridge pattern allows
you to add new devices without modifying the remote control code.
C# Code Example:
// Abstraction
void TurnOn();
void TurnOff();
// Refined Abstraction
_device = device;
_device.TurnOn();
_device.TurnOff();
_device.SetChannel(channel);
_device.Mute();
// Implementor
void TurnOn();
void TurnOff();
void Mute();
// Concrete Implementors
{
Console.WriteLine("Muting the TV.");
}
}
// Client code
remote.TurnOn();
remote.SetChannel(10);
((AdvancedRemoteControl)remote).Mute();
remote.TurnOn();
Explanation: This example shows how different types of devices (TV and DVDPlayer) can be controlled
using a RemoteControl abstraction, and how new devices can be added without modifying the remote
control code.
8. Composite
Purpose: Composes objects into tree structures to represent part-whole hierarchies.
What it is: A structural pattern that lets you treat individual objects and compositions of objects
uniformly, allowing you to build complex hierarchies where both individual objects (leaves) and
groups of objects (composites) can be treated the same.
Benefits:
o Simplifies the client code by providing a unified way to interact with both individual
objects and groups of objects.
o Makes it easy to add or remove components in the hierarchy without affecting the client
code.
o Promotes flexibility and extensibility by allowing for dynamic changes in the structure.
o When you want to treat individual objects and compositions of objects uniformly.
1. Define a component interface that declares common operations for both leaf objects and
composite objects.
2. Create concrete leaf classes that implement the component interface for individual objects.
3. Create a composite class that also implements the component interface and contains a collection
of child components.
Real-world example: Think of a file system structure: directories (composites) can contain files
(leaves) and other directories, allowing you to navigate and manage the entire structure as a single
entity.
C# Code Example:
// Component interface
Name = name;
Console.WriteLine($"File: {Name}");
Name = name;
_children.Add(component);
_children.Remove(component);
Console.WriteLine($"Directory: {Name}");
component.Display();
// Client code
public class Client
root.Add(documents);
root.Add(pictures);
documents.Add(file1);
documents.Add(file2);
pictures.Add(file3);
pictures.Add(file4);
root.Display();
}
Explanation: This example demonstrates how a file system can be represented using the Composite
pattern, allowing for the uniform treatment of files and directories. The Display method recursively
traverses the hierarchy and displays the contents.
9. Decorator
Purpose: Attaches additional responsibilities to an object dynamically.
What it is: A structural pattern that lets you add new functionalities to an object dynamically
without altering its structure. Decorators provide a flexible alternative to subclassing for
extending functionality.
Benefits:
o When you want to extend functionality without creating a large number of subclasses.
1. Define a component interface that declares common operations for both the concrete component
and decorators.
2. Create a concrete component class that implements the component interface and provides the
basic functionality.
3. Create decorator classes that implement the component interface and contain a reference to a
component object. Decorators add their own behavior before or after delegating to the component.
Real-world example: Imagine a coffee shop where you can add various toppings (decorators) to
a basic coffee (component) like whipped cream, chocolate sprinkles, or caramel. Each topping
adds its cost and description to the coffee.
C# Code Example:
// Component interface
string GetDescription();
decimal GetCost();
return 2.0m;
_coffee = coffee;
// Client code
{
// Order a simple coffee
Explanation: This example demonstrates how decorators can be used to add toppings to a basic coffee,
dynamically altering its description and cost.
10. Facade
Purpose: Provides a simplified interface to a complex subsystem.
What it is: A structural pattern that hides the complexity of a subsystem behind a simpler
interface, making it easier to use and understand. The facade acts as a single point of entry to the
subsystem, providing a high-level interface to the client.
Benefits:
o Makes the subsystem easier to use and understand by providing a simplified interface.
o Decouples the client code from the subsystem, making it easier to modify the subsystem
without affecting the client.
o When you want to decouple the client code from the subsystem.
1. Identify the subsystem classes that the client needs to interact with.
3. Implement the facade methods by delegating to the appropriate methods of the subsystem classes.
Real-world example: Think of a home theater system with multiple components (DVD player,
amplifier, projector, screen). A facade can provide a simplified interface with methods like
WatchMovie() or ListenToMusic(), hiding the complexity of managing each component
individually.
C# Code Example:
// Subsystem classes
Console.WriteLine("Amplifier is on.");
Console.WriteLine("Amplifier is off.");
}
public void SetVolume(int level)
}
public class Projector
Console.WriteLine("Projector is on.");
Console.WriteLine("Projector is off.");
// Facade class
_amplifier = amplifier;
_dvdPlayer = dvdPlayer;
_projector = projector;
_amplifier.On();
_dvdPlayer.On();
_projector.On();
_projector.WideScreenMode();
_amplifier.SetVolume(5);
_dvdPlayer.Play(movie);
_amplifier.Off();
_dvdPlayer.Off();
_projector.Off();
}
}
// Client code
homeTheater.WatchMovie("Inception");
homeTheater.EndMovie();
Explanation: The HomeTheaterFacade class provides a simplified interface for controlling the home
theater components, hiding the complexities of managing each component individually.
11. Flyweight
Purpose: Shares objects to support large numbers of fine-grained objects efficiently.
What it is: A structural pattern that minimizes memory usage by sharing common state among
multiple objects. Flyweights store intrinsic state (shared) and extrinsic state (unique) separately,
allowing for significant memory savings when dealing with large numbers of similar objects.
Benefits:
o When the objects have intrinsic state that can be shared, and extrinsic state that can be
passed in as parameters.
1. Define a flyweight interface that declares methods for accessing and manipulating the flyweight's
intrinsic state.
2. Create concrete flyweight classes that implement the flyweight interface and store the intrinsic
state.
3. Create a flyweight factory that manages the flyweight objects, ensuring that only one instance of
a flyweight with a specific intrinsic state is created.
Real-world example: Imagine a word processor where each character is an object. Using
flyweights, you can share the font and size data (intrinsic state) among all instances of the same
character, reducing memory usage significantly.
C# Code Example:
// Flyweight interface
}
// Concrete Flyweight class
// Flyweight Factory
{
private Dictionary<char, ICharacter> _characters = new Dictionary<char, ICharacter>();
if (!_characters.ContainsKey(key))
switch (key)
case 'A':
break;
case 'B':
break;
default:
return _characters[key];
// Client code
Explanation: In this example, the flyweight objects (CharacterA, CharacterB) store the intrinsic state (the
character symbol). The extrinsic state (point size, font, and color) is passed in as parameters to the
Display method. The CharacterFactory ensures that only one instance of each character is created.
12. Proxy
Purpose: Provides a surrogate or placeholder for another object to control access to it.
What it is: A structural pattern that provides a substitute or placeholder for a real object. The
proxy controls access to the real object, allowing you to perform operations like access control,
caching, logging, or lazy initialization.
Benefits:
o When you need to control access to an object (e.g., for security reasons).
o When you want to add additional functionality to an object without modifying it directly.
o When you want to delay the creation of an object until it's actually needed.
1. Define a subject interface that is implemented by both the real subject and the proxy.
3. Create a proxy class that implements the subject interface and contains a reference to the real
subject. The proxy controls access to the real subject.
Real-world example: Imagine an image gallery application that displays thumbnails of large
images. You can use a proxy to represent the image and only load the full-size image when the
user clicks on the thumbnail.
C# Code Example:
// Subject interface
void Display();
// Real Subject
public class RealImage : IImage
_fileName = fileName;
LoadFromDisk();
// Proxy
_fileName = fileName;
if (_realImage == null)
_realImage.Display();
// Client code
image1.Display();
image2.Display();
Explanation: This example shows how the ImageProxy class acts as a proxy for the RealImage class,
loading the image from disk only when the Display method is called.
This covers the Structural Patterns in our Design Pattern journey. Next, we'll explore the Behavioral
Patterns! Let me know if you have any questions so far.
What it is: A behavioral pattern that creates a chain of handler objects. Each handler has the
option to process a request or pass it on to the next handler in the chain.
Benefits:
o When multiple objects can handle a request, and the handler should be determined at
runtime.
o When you want to avoid coupling the sender of a request to its receiver.
o When the set of handlers and their order may change dynamically.
2. Create concrete handler classes that implement the handler interface, each responsible for
handling a specific type of request.
3. Chain the handlers together, typically by setting the NextHandler property of each handler to the
next handler in the chain.
4. The client sends the request to the first handler in the chain. Each handler checks if it can handle
the request; if not, it passes the request to the next handler.
Real-world example: Imagine a customer support system where different levels of support
agents handle different types of issues. A basic issue can be resolved by a level 1 agent, while a
more complex issue might be escalated to a level 2 agent.
C# Code Example:
// Handler interface
this._nextHandler = handler;
return handler;
if (this._nextHandler != null)
return this._nextHandler.Handle(request);
else
return null;
{
return $"BasicSupportHandler: I can handle this. Issue resolved.";
else
return base.Handle(request);
else
return base.Handle(request);
}
// Issue class representing a support issue
// Client code
basicHandler.SetNext(advancedHandler);
Explanation: In this example, the BasicSupportHandler handles basic issues, while the
AdvancedSupportHandler handles advanced issues. If an issue is not handled by either handler, it falls
through the chain and returns null.
14. Command
Purpose: Encapsulates a request as an object, thereby letting you parameterize clients with
different requests, queue or log requests, and support undoable operations.
What it is: A behavioral pattern that encapsulates a request as an object, allowing for
parameterization, queuing, logging, and undo/redo functionalities.
Benefits:
o Decouples the object that invokes the request from the object that knows how to perform
it.
2. Create concrete command classes that implement the command interface, each encapsulating a
specific request.
3. Create an invoker object that holds and invokes the commands.
4. The client creates command objects and sets them on the invoker. The invoker then executes the
commands.
Real-world example: Think of a text editor where each editing action (typing, deleting,
formatting) is a command. These commands can be queued, logged, and undone/redone,
providing a flexible and powerful editing experience.
C# Code Example:
// Command interface
void Execute();
void Undo();
_light = light;
{
_light.TurnOn();
_light.TurnOff();
_light = light;
_light.TurnOff();
_light.TurnOn();
// Receiver class
Console.WriteLine("Light is ON");
Console.WriteLine("Light is OFF");
// Invoker class
_command = command;
_command.Execute();
_command.Undo();
// Client code
remote.SetCommand(new TurnOffLightCommand(light));
Explanation: This example shows how a RemoteControl (Invoker) can be used to execute and undo
Light (Receiver) commands (TurnOnLightCommand, TurnOffLightCommand).
15. Interpreter
Purpose: Given a language, defines a representation for its grammar along with an interpreter
that uses the representation to interpret sentences in the language.
What it is: A behavioral pattern that defines a grammatical representation for a language and
provides an interpreter to deal with this grammar.
Benefits:
o When the grammar is relatively simple and can be represented using a recursive structure.
How to use it:
1. Define a grammar for the language using a context-free grammar or similar formalism.
3. Create concrete expression classes that implement the abstract expression classes, each
representing a specific terminal or non-terminal symbol in the grammar.
4. Create an interpreter class that traverses the abstract syntax tree (AST) generated from the input
string, interpreting each expression according to the grammar rules.
Real-world example: Consider a system that evaluates mathematical expressions. You can use
the Interpreter pattern to define the grammar for mathematical expressions and create an
interpreter that evaluates them.
C# Code Example:
int Interpret();
_number = number;
}
public int Interpret()
return _number;
_leftExpression = leftExpression;
_rightExpression = rightExpression;
}
// Non-terminal expression for subtraction
_leftExpression = leftExpression;
_rightExpression = rightExpression;
// Client code
new SubtractExpression(
new NumberExpression(2),
new NumberExpression(3)
);
Explanation: This example defines a simple grammar for mathematical expressions with addition and
subtraction. The Interpreter pattern is used to build an expression tree from the input and then interpret the
tree to calculate the result.
16. Iterator
Purpose: Provides a way to access the elements of an aggregate object sequentially without
exposing its underlying representation.
What it is: A behavioral pattern that provides a way to traverse the elements of a collection
without exposing its underlying structure.
Benefits:
o Simplifies the client code by hiding the details of the iteration process.
o Allows for multiple iterations over the same collection without interfering with each
other.
When to use it:
o When you want to provide a way to access the elements of a collection without exposing
its internal structure.
o When you want to support different types of iterations (e.g., forward, backward, filtered).
1. Define an iterator interface that declares methods for traversing the collection (e.g., HasNext,
Next, Current).
2. Create concrete iterator classes that implement the iterator interface, each specific to a type of
collection.
3. Implement an iterator() method in the aggregate class that returns an instance of the appropriate
iterator.
Real-world example: Think of a music playlist. You can use an iterator to go through each song
in the playlist without knowing how the songs are stored internally (e.g., array, linked list, etc.).
C# Code Example:
// Iterator interface
bool HasNext();
T Next();
// Aggregate interface
IIterator<T> CreateIterator();
}
// Concrete aggregate (a collection of names)
// Concrete iterator
_names = names;
return _names[_index++];
// Client code
// Get an iterator
while (iterator.HasNext())
Console.WriteLine($"Name : {iterator.Next()}");
}
Explanation: This example shows how an iterator (NameIterator) can be used to traverse the elements of
a NameRepository without exposing its internal structure.
17. Mediator
Purpose: Defines an object that encapsulates how a set of objects interact.
What it is: A behavioral pattern that promotes loose coupling between objects by introducing a
mediator object. The mediator acts as a central hub for communication between objects, reducing
direct dependencies between them.
Benefits:
o Reduces coupling between objects, making the system more flexible and maintainable.
o When you want to reuse objects in different contexts but their interactions are context-
dependent.
1. Define a mediator interface that declares methods for communication between colleagues.
2. Create concrete mediator classes that implement the mediator interface and coordinate
communication between colleagues.
3. Create colleague classes that hold a reference to the mediator and communicate through it.
Real-world example: Imagine an air traffic control tower. The tower (mediator) coordinates
communication between airplanes (colleagues), ensuring safe and efficient air traffic.
C# Code Example:
// Mediator interface
// Concrete Mediator
_users.Add(user);
if (u != user)
u.Receive(message);
}
}
// Colleague
_name = name;
_chatroom = chatroom;
_chatroom.SendMessage(message, this);
}
// Client code
chatroom.RegisterUser(user1);
chatroom.RegisterUser(user2);
chatroom.RegisterUser(user3);
// Send messages
Explanation: This example shows how a Chatroom (mediator) facilitates communication between User
(colleague) objects, ensuring that messages are delivered to the correct recipients.
18. Memento
Purpose: Without violating encapsulation, captures and externalizes an object's internal state so
that the object can be restored to this state later.
What it is: A behavioral pattern that allows you to save and restore an object's internal state
without exposing its internal structure.
Benefits:
o Preserves encapsulation by hiding the object's internal state from other objects.
1. Create a memento class that stores the internal state of the originator object.
2. Create an originator class that has methods for creating a memento and restoring its state from a
memento.
3. Create a caretaker class that holds and manages the memento objects.
Real-world example: Consider a text editor. The Memento pattern can be used to implement the
undo/redo functionality, allowing the user to revert the text editor to a previous state.
C# Code Example:
// Memento class
public class EditorMemento
_content = content;
return _content;
// Originator class
_content = content;
}
public string GetContent()
return _content;
_content = memento.GetContent();
// Caretaker class
_mementos.Push(memento);
}
public EditorMemento Pop()
return _mementos.Pop();
// Client code
// Initial content
editor.SetContent("Hello World");
history.Push(editor.CreateMemento());
// Change content
editor.SetContent("Hello Universe");
history.Push(editor.CreateMemento());
editor.SetContent("Hello Galaxy");
// Restore to the previous state
editor.RestoreFromMemento(history.Pop());
editor.RestoreFromMemento(history.Pop());
Explanation: This example demonstrates how a History (caretaker) object can store EditorMemento
objects, which represent the state of a TextEditor (originator) at different points in time, allowing for
undo/redo functionality.
19. Observer
Purpose: Defines a one-to-many dependency between objects so that when one object changes
state, all its dependents are notified and updated automatically.
What it is: A behavioral pattern where a "subject" object maintains a list of its dependents, called
"observers," and notifies them automatically of any state changes, usually by calling one of their
methods.
Benefits:
o Establishes a loose coupling between the subject and its observers, making the system
more flexible and maintainable.
o Provides an efficient way for the subject to notify its dependents without having to know
about their specific implementations.
o When you want to decouple the subject from its observers, allowing them to change
independently.
1. Define a subject interface with methods for attaching and detaching observers and notifying them.
2. Create a concrete subject class that implements the subject interface and maintains a list of
observers.
3. Define an observer interface with an Update method that will be called by the subject when its
state changes.
4. Create concrete observer classes that implement the observer interface and define the actions to
be performed when the subject's state changes.
Real-world example: A news agency (subject) can notify its subscribers (observers) when new
news articles are published.
C# Code Example:
// Subject interface
void Notify();
// Concrete Subject
set
_latestNews = value;
Notify();
_observers.Add(observer);
_observers.Remove(observer);
observer.Update(this);
// Observer interface
// Concrete Observer
_name = name;
// Client code
// Create subscribers
newsAgency.Attach(subscriber1);
newsAgency.Attach(subscriber2);
newsAgency.Detach(subscriber1);
Explanation: This example demonstrates how the NewsAgency (Subject) notifies its NewsSubscriber
(Observer) objects when there's an update to the LatestNews.
20. State
Purpose: Allows an object to alter its behavior when its internal state changes.
What it is: A behavioral pattern that allows an object to change its behavior based on its internal
state. The object delegates its behavior to a state object, which represents a particular state.
Benefits:
o Makes it easier to add or modify states without affecting the context object.
1. Define a state interface that declares methods for the state-specific behavior.
2. Create concrete state classes that implement the state interface, each representing a different state.
3. Create a context class that contains a reference to the current state object and delegates requests to
it.
Real-world example: Consider a vending machine. The vending machine's behavior changes
based on its state (e.g., has money, no money, dispensing item).
C# Code Example:
// State interface
machine.SetState(machine.HasQuarterState);
Console.WriteLine("Quarter returned.");
machine.SetState(machine.NoQuarterState);
}
Console.WriteLine("You turned...");
machine.SetState(machine.SoldState);
if (machine.Count > 0)
machine.SetState(machine.NoQuarterState);
else
machine.SetState(machine.SoldOutState);
{
public void InsertQuarter(VendingMachine machine)
// Context
Count = count;
if (count > 0)
_state = NoQuarterState;
else
_state = SoldOutState;
_state = state;
_state.InsertQuarter(this);
_state.EjectQuarter(this);
_state.TurnCrank(this);
_state.Dispense(this);
// Client code
machine.InsertQuarter();
machine.TurnCrank();
machine.InsertQuarter();
machine.EjectQuarter();
machine.TurnCrank();
machine.InsertQuarter();
machine.TurnCrank();
Explanation: The VendingMachine (Context) class holds a reference to the current state (_state) and
delegates the behavior to the corresponding state object.
21. Strategy
Purpose: Defines a family of algorithms, encapsulates each one, and makes them
interchangeable.
What it is: A behavioral pattern that lets you define a family of algorithms, encapsulate each one
into a separate class, and make them interchangeable. This allows the algorithm used by a client
to be selected at runtime.
Benefits:
o Makes it easy to add or remove algorithms without modifying the client code.
o When you want to avoid using conditional statements to choose between different
algorithms.
1. Define a strategy interface that declares the common methods for all algorithms.
2. Create concrete strategy classes that implement the strategy interface, each representing a
different algorithm.
3. Create a context class that uses a strategy object to perform the operation.
4. The client chooses the strategy to use and sets it on the context object.
Real-world example: Imagine a navigation app that provides different routing algorithms (fastest
route, shortest route, most scenic route). The user can choose the routing algorithm based on their
preferences.
C# Code Example:
// Strategy interface
// Context class
_routeStrategy = routeStrategy;
_routeStrategy = routeStrategy;
_routeStrategy.CalculateRoute(origin, destination);
// Client code
navigator.SetStrategy(new ShortestRouteStrategy());
navigator.Navigate("London", "Paris");
}
Explanation: This example shows how the Navigator (Context) uses different RouteStrategy (Concrete
Strategies) to calculate routes. The client can dynamically change the strategy at runtime, allowing for
flexibility in choosing the routing algorithm.
What it is: A behavioral pattern that defines the overall structure of an algorithm in a base class,
allowing subclasses to override specific steps without changing the algorithm's structure.
Benefits:
o Promotes code reuse by defining a common algorithm structure in the base class.
o When you want to define an algorithm's invariant parts in a base class and allow
subclasses to define variant parts.
1. Define a template method in the base class that outlines the algorithm's steps.
2. Declare abstract methods (or hook methods with default implementations) in the base class for
the steps that can be overridden by subclasses.
3. Create concrete subclasses that override the abstract methods to provide specific implementations
for those steps.
Real-world example: Think of a process for making different types of beverages (coffee, tea, hot
chocolate). The Template Method pattern can define the common steps (boil water, add
ingredients, steep/brew, serve), while subclasses override specific steps like the type of
ingredients or brewing method.
C# Code Example:
BoilWater();
Brew();
PourInCup();
AddCondiments();
// Common operations
Console.WriteLine("Boiling water...");
Console.WriteLine("Adding Lemon...");
// Client code
// Prepare coffee
coffee.PrepareRecipe();
Console.WriteLine();
// Prepare tea
tea.PrepareRecipe();
Explanation: This example shows how the Beverage class defines the template method PrepareRecipe(),
outlining the common steps for making a beverage. The subclasses Coffee and Tea provide concrete
implementations for the Brew and AddCondiments methods, customizing the steps specific to each
beverage.
23. Visitor
Purpose: Represents an operation to be performed on the elements of an object structure.
What it is: A behavioral pattern that lets you define new operations to be performed on elements
of an object structure (like a tree or a list) without modifying the structure itself. The visitor
object "visits" each element and performs the specific operation on it.
Benefits:
o Adds new operations to a class hierarchy without modifying the classes themselves.
o When you want to add operations to a class hierarchy without modifying the classes.
o When the operations you want to perform vary depending on the concrete type of the
object.
1. Define a visitor interface with Visit methods for each concrete element type in the object
structure.
2. Create concrete visitor classes that implement the visitor interface, each providing the specific
implementation for the operation on the corresponding element type.
3. Add an Accept method to the element interface that takes a visitor object as a parameter.
4. Implement the Accept method in each concrete element class to call the appropriate Visit method
on the visitor, passing itself as an argument.
Real-world example: Imagine a compiler that needs to perform different operations on different
parts of the code (e.g., checking variable declarations, analyzing expressions, generating code).
The Visitor pattern can be used to define visitors for each of these operations, allowing new
operations to be added without modifying the code structure.
C# Code Example:
// Element interface
Console.WriteLine("ConcreteElementA: OperationA");
visitor.VisitConcreteElementA(this);
{
Console.WriteLine("ConcreteElementB: OperationB");
visitor.VisitConcreteElementB(this);
// Visitor interface
element.OperationA();
}
public void VisitConcreteElementB(ConcreteElementB element)
element.OperationB();
// Client code
new ConcreteElementA(),
new ConcreteElementB()
};
// Create visitor
{
element.Accept(visitor1);
Explanation: This example shows how the ConcreteVisitor1 performs specific operations on each
element in the list, demonstrating the core concept of the Visitor pattern in separating operations from the
object structure.
These comprehensive explanations should give you a solid understanding of both the Structural and
Behavioral Design Patterns. Remember, choosing the right pattern depends on the specific problem you're
trying to solve and the context of your application. Good Luck!
Rgds/ManhNC5