0% found this document useful (0 votes)
12 views17 pages

Structural Design Patterns (1)

Structural Design Patterns focus on organizing classes and objects to create efficient software structures, simplifying relationships and supporting code reuse. Key patterns include Adapter, Bridge, Composite, Decorator, Facade, Flyweight, and Proxy, each serving unique purposes like integrating incompatible interfaces, enhancing functionality dynamically, and providing simplified interfaces to complex systems. These patterns promote maintainability and scalability in software design.

Uploaded by

haifa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views17 pages

Structural Design Patterns (1)

Structural Design Patterns focus on organizing classes and objects to create efficient software structures, simplifying relationships and supporting code reuse. Key patterns include Adapter, Bridge, Composite, Decorator, Facade, Flyweight, and Proxy, each serving unique purposes like integrating incompatible interfaces, enhancing functionality dynamically, and providing simplified interfaces to complex systems. These patterns promote maintainability and scalability in software design.

Uploaded by

haifa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Structural Design Patterns

Structural Design Patterns focus on organizing classes and objects to build larger, efficient, and
maintainable software structures. They simplify relationships, support code reuse, and help create
scalable architectures.

There are two recurring themes in these patterns:

• This pattern is particularly useful for making independently developed class libraries work
together.

• Structural Design Patterns describe ways to compose objects to realize new functionality.

• The added flexibility of object composition comes from the ability to change the composition
at run-time, which is impossible with static class composition.

• Types of Structural Design Patterns


There are mainly 7 types of creational design patterns:

[Link] Design Pattern

Adapter Design Pattern is a structural pattern that acts as a bridge


between two incompatible interfaces, allowing them to work together. It
is especially useful for integrating legacy code or third-party libraries into
a new system.
• It enables classes with incompatible interfaces to collaborate without
modifying their source code.
• It promotes code reusability by allowing existing functionality to be used
in new systems.
• It can be implemented in two ways: Class Adapter (using inheritance) and
Object Adapter (using composition).

• Client wants to use a Target interface (it calls Request()).


• Adaptee already has useful functionality, but its method
(SpecificRequest()) doesn’t match the Target interface.
• Adapter acts as a bridge: it implements the Target interface (Request()),
but inside, it calls the Adaptee’s SpecificRequest().
• This allows the Client to use the Adaptee without changing its code.
Working
Below is how adapter design pattern works:
• Step 1: The client initiates a request by calling a method on the adapter
via the target interface.
• Step 2: The adapter maps or transforms the client's request into a format
that the adaptee can understand using the adaptee's interface.
• Step 3: The adaptee does the actual job based on the translated request
from the adapter.
• Step 4: The client receives the results of the call, remaining unaware of
the adapter's presence or the specific details of the adaptee.
Uses Of Adapter Design Pattern
We can use adapter design pattern when:
• Enables communication between incompatible systems.
• Reuses existing code or libraries without rewriting.
• Simplifies integration of new components, keeping the system flexible.
• Centralizes compatibility changes, making maintenance easier and safer.
Components
Below are the components of adapter design pattern:
• Target Interface: The interface expected by the client, defining the
operations it can use.
• Adaptee: The existing class with an incompatible interface that needs
integration.
• Adapter: Implements the target interface and uses the adaptee internally,
acting as a bridge.
• Client: Uses the target interface, unaware of the adapter or adaptee
details.
Different implementations
The Adapter Design Pattern can be applied in various ways depending on
the programming language and the specific context. Here are the primary
implementations:
1. Class Adapter (Inheritance-based)
• In this approach, the adapter class inherits from both the target interface
(the one the client expects) and the adaptee (the existing class needing
adaptation).
• Programming languages that allow multiple inheritance, like C++, are
more likely to use this technique.
• However, in languages like Java and C#, which do not support multiple
inheritance, this approach is less frequently used.
2. Object Adapter (Composition-based)
• The object adapter employs composition instead of inheritance. In this
implementation, the adapter holds an instance of the adaptee and
implements the target interface.
• This approach is more flexible as it allows a single adapter to work with
multiple adaptees and does not require the complexities of inheritance.
• The object adapter is widely used in languages like Java and C#.
3. Two-way Adapter
• A two-way adapter can function as both a target and an adaptee,
depending on which interface is being invoked.
• This type of adapter is particularly useful when two systems need to work
together and require mutual adaptation.
4. Interface Adapter (Default Adapter)
• When only a few methods from an interface are necessary, an interface
adapter can be employed.
• This is especially useful in cases where the interface contains many
methods, and the adapter provides default implementations for those
that are not needed.
• This approach is often seen in languages like Java, where abstract classes
or default method implementations in interfaces simplify the
implementation process.
[Link] Design Pattern

The Bridge design pattern allows you to separate the abstraction from the implementation. It is a
structural design pattern.

There are 2 parts in Bridge design pattern :

1. Abstraction

2. Implementation

This is a design mechanism that encapsulates an implementation class inside of an interface class.

• The bridge pattern allows the Abstraction and the Implementation to be developed
independently and the client code can access only the Abstraction part without being
concerned about the Implementation part.

• The abstraction is an interface or abstract class and the implementer is also an interface or
abstract class.

• The abstraction contains a reference to the implementer. Children of the abstraction are
referred to as refined abstractions, and children of the implementer are concrete
implementers. Since we can change the reference to the implementer in the abstraction, we
are able to change the abstraction's implementer at run-time. Changes to the implementer
do not affect client code.

• It increases the loose coupling between class abstraction and it’s implementation.

UML Diagram of Bridge Design Pattern


Elements of Bridge Design Pattern

• Abstraction – core of the bridge design pattern and defines the crux. Contains a reference to
the implementer.

• Refined Abstraction – Extends the abstraction takes the finer detail one level below. Hides
the finer elements from implementers.

• Implementer – It defines the interface for implementation classes. This interface does not
need to correspond directly to the abstraction interface and can be very different.
Abstraction imp provides an implementation in terms of operations provided by the
Implementer interface.

• Concrete Implementation – Implements the above implementer by providing the concrete


implementation.

3. Composite Design Pattern in Java

The Composite Design Pattern is a structural pattern that organizes objects into tree
structures, allowing clients to treat individual objects and groups of objects uniformly.

As described by the Gang of four, "Compose objects into tree structure to represent part-
whole hierarchies. Composite lets client treat individual objects and compositions of objects
uniformly".

Components of Composite Design Pattern

Let's understand this with the help of Diagram:


Here These are introductions for the Components of the Composite Design:

• Component – Defines a common interface that both leaf objects and composite objects
implement.

• Leaf – Represents simple, indivisible objects that perform operations directly.

• Composite – Represents complex objects that can contain children (leaves or other
composites) and delegate operations to them.

• Client – Works with all objects through the Component interface, treating individual and
composite objects uniformly.

4. Decorator Design Pattern

The Decorator Design Pattern is a structural pattern that allows behavior to be added to individual
objects dynamically. It enhances functionality without modifying the original class or affecting other
objects.

• Uses decorator classes to wrap existing objects.

• Adds new behavior at runtime instead of compile time.

• Promotes flexibility by avoiding subclass explosion.

• Follows the open/closed principle by extending functionality without altering existing code.

Decorator Design Pattern

• This represents Pizza as the base component.

• Capsicum acts as the first decorator, wrapping the pizza and adding its own cost using
getCost().

• Cheese Burst is another decorator that wraps the previous layer and adds additional cost.

• The final price is calculated as Pizza + Capsicum + Cheese Burst, demonstrating how the
Decorator Pattern adds behavior dynamically.
Components

1. Component Interface: Defines common operations for components and decorators.

2. Concrete Component: Core object with basic functionality.

3. Decorator: Abstract wrapper that holds a Component reference and adds behavior.

4. Concrete Decorator: Specific decorators that extend functionality of the component.

Working

1. Define a component interface that both the core object and decorators implement.

2. Create a concrete component that implements the interface.

3. Create decorator classes that also implement the interface and have a reference to a
component object.

4. Decorator classes add or override behavior by delegating to the wrapped object.

Use of Decorator Pattern

The Decorator Pattern is used when:

• You want to add responsibilities to objects without subclassing.

• You need to combine behaviors flexibly at runtime.

• You want to extend functionality of a class in a transparent way.

5. Facade Method Design Pattern

The Facade Design Pattern is a structural pattern that provides a simple, unified interface to a
complex subsystem. It hides internal complexity, making the system easier to use and maintain.
• Structuring a system into subsystems helps reduce complexity.

• A common design goal is to minimize the communication and dependencies between


subsystems.

• One way to achieve this goal is to introduce a Facade object that provides a single simplified
interface to the more general facilities of a subsystem.

Note: Facade Method Design Pattern provides a unified interface to a set of interfaces in a subsystem.
Facade defines a high-level interface that makes the subsystem easier to use.

Real Life Use of Facade Design Pattern

1. Home Automation Systems

• Provides a single interface to control lighting, heating, and security systems.

• Hides the complexity of multiple underlying subsystems.

2. Video Streaming Platforms

• Offers a unified interface for encoding, buffering, and video playback.

• Simplifies interaction with complex media processing components.

3. Banking Systems

• Exposes simple methods for operations like balance checks and fund transfers.

• Conceals complex backend processes from the client.

4. Car Engine Start-up

• Coordinates subsystems such as fuel injection, ignition, and starter motor.

• Allows the engine to start with a single method call.

Use of Facade Method Design Pattern


1. Simplifying Complex External Systems

• Encapsulates complex operations such as database handling or third-party APIs.

• Hides internal implementation details from the client.

2. Layering Subsystems

• Defines clear boundaries between different subsystems.

• Provides simplified interfaces for interacting with each layer.

3. Providing a Unified Interface to Diverse Systems

• Combines multiple APIs into a single, easy-to-use interface.

• Helps modernize and integrate legacy systems.

4. Protecting Clients from Unstable Systems

• Maintains a stable interface even if internal systems change.

• Shields client code from frequent updates or breaking changes.

Components of Facade Method Design Pattern


Consider for example a programming environment that gives applications access to its compiler
subsystem.

• This subsystem contains classes such as Scanner,Parser, ProgramNode, BytecodeStream,


and ProgramNodeBuilder that implement the compiler.

• Compiler class acts as a facade: It offers clients a single, simple interface to the
compilersubsystem.

• It glues together the classes that implement compilerfunctionality without hiding


themcompletely.

• The compiler facade makes life easier for most programmers without hiding the lower-
level functionality from the few that need it.

1. Facade (Compiler)

• Facade knows which subsystem classes are responsible for a request.

• It delegate client requests to appropriate subsystem objects.

2. Subsystem classes (Scanner, Parser, ProgramNode, etc.)

• It implement subsystem functionality.

• It handle work assigned by the Facade object.

• It have no knowledge of the facade; that is, they keep no references to it.

3. Interface

• The Interface in the Facade Design Pattern refers to the set of simplified methods that the
facade exposes to the client.

• It hides the complexities of the subsystem, ensuring that clients interact only with high-
level operations, without dealing with the underlying details of the system.

Steps to implement Facade Design Pattern


Step 1: First, determine the complex subsystems or components that the client needs to interact
with.

Step 2: Build a facade class that serves as the middle layer between the client and the subsystems.
This class should offer simplified methods that wrap the interactions with the subsystems.

Step 3: Expose a clear, high-level interface in the facade class. This interface will include the
methods that the client will use, hiding the internal complexity.

Step 4: Inside the facade methods, delegate the requests to the appropriate subsystem classes to
perform the actual operations.

Step 5: The client now interacts only with the facade, which manages the underlying calls to the
subsystems, simplifying the client’s experience.

How the Facade Design Pattern Collaborates?

• The Facade acts as an intermediary between the client and the subsystem.

• Clients send requests to the Facade instead of interacting with subsystem components
directly.

• The Facade delegates these requests to the appropriate subsystem objects.

• It may perform additional processing or translation to adapt client requests to subsystem


interfaces.

• This approach keeps clients independent of subsystem complexity.

6. Flyweight Design Pattern

The Flyweight Design Pattern is a way to save memory in applications that create a large number of
similar objects. Instead of creating a new object for each instance, the Flyweight pattern reuses
existing ones wherever possible, sharing common parts between objects.

Here’s how it works:

• Shared vs. Unique Data: Objects are split into shared (intrinsic) data and unique (extrinsic)
data. The shared data is stored in a central place and reused, while the unique data is kept
separately.

• Example: Imagine a text editor displaying thousands of characters. Using Flyweight, the
program can store each unique character style (like font or color) only once and reuse it,
rather than duplicating it for every character.

Components of Flyweight Design Pattern

The Flyweight design pattern typically consists of the following components:


1. Flyweight Interface/Class:

• Defines the interface through which flyweight objects can receive and act on extrinsic state.

2. Concrete Flyweight Classes:

• Implements the Flyweight interface and represents objects that can be shared.

• Stores intrinsic state (state that can be shared) and provides methods to manipulate intrinsic
state if needed.

3. Flyweight Factory:

• Manages a pool of flyweight objects.

• Provides methods for clients to retrieve or create flyweight objects.

• Ensures flyweight objects are shared appropriately to maximize reusability.

4. Client:

• Uses flyweight objects to perform operations.

• Maintains or passes extrinsic state to flyweight objects when needed.

• Does not manage the lifecycle of flyweight objects directly but interacts with them via the
factory.

Implementation of Flyweight Design Pattern

To implement the Flyweight Design Pattern, follow these simple steps:

• Step 1: Identify Shared and Unique Data: Arrange the data in your objects first. Determine
which information is specific to each object (known as extrinsic data) and which can be
shared across objects (known as intrinsic data).

• Step 2: Create a Flyweight Class: This class will hold the intrinsic (shared) data. All instances
of this class represent objects with similar data.
• Step 3: Build a Flyweight Factory: This factory class manages instances of the Flyweight
objects. When a new object is needed, the factory checks if an object with the same shared
data already exists. If it does, it reuses that object; if not, it creates a new one.

• Step 4: Pass Unique Data as Needed: The extrinsic data, or data specific to that
instance(extrinsic data), should be passed as a parameter when using an object. In this
manner, the object can act in a unique way without storing all of the data.

• Step 5: Use Flyweights Instead of Creating New Objects: Now, instead of creating new
objects directly, always request them through the factory. The factory will manage all shared
instances and reuse them where possible.

7. Proxy Method Design Pattern

Proxy Method Design Pattern also known as Surrogate, provides a surrogate or placeholder for
another object to control access to it.

Use of Proxy Method Pattern

Proxy method is applicable whenever there is a need for a more versatile or sophisticated reference
to an object than a simple pointer. Here are several common situations in which the Proxy pattern is
applicable:

• A remote proxy provides a local representative for an object in a different address space.

• A virtual proxy creates expensive objects on demand.

• A protection proxy controls access to the original object. Protection proxies are useful when
objects should have different access rights

• A smart reference is a replacement for a bare pointer that performs additional actions when
an object is accessed.

Importance of Structural Design Patterns

Structural patterns provide several key benefits:

• Simplify Code: Structural patterns help organize and simplify code by connecting objects and
classes in a clear way, making complex relationships easier to understand and manage.

• Reduce Duplicate Code: By reusing existing structures, structural patterns avoid duplicate
code, which makes your program more efficient and less prone to errors.

• Enhance Flexibility: These patterns allow you to add or change features without altering
existing code too much, making the program easier to extend or modify.

• Improve Readability: They provide a clear structure that organizes classes and objects,
making it easier for others to understand and maintain the code.

• Optimize Resource Use: Structural patterns like Flyweight help reduce memory usage and
improve performance by sharing common data among objects instead of duplicating it.

Challenges of Structural Design Patterns

Using structural patterns also comes with some challenges:


• Increased Complexity: Structural patterns like Decorator or Proxy can add layers to the code,
making it harder to read and follow. If too many patterns are used, the code can become
overly complex.

• Performance Issues: Some patterns, such as Flyweight, may need extra processing to
manage shared objects. This can lead to slower performance if not used carefully.

• Overhead in Maintenance: As structural patterns add more classes and interfaces, it can be
harder to maintain or update the code. New developers may need more time to understand
how everything fits together.

• Risk of Overengineering: It’s easy to overuse patterns, which leads to unnecessary


abstraction. Sometimes, simpler code without patterns is more effective and easier to work
with.

• Difficulty in Debugging: With extra layers, tracing bugs can become challenging since the
problem might be hidden deep within the pattern structure.

Behavioral Design Patterns

Behavioral design patterns are a category of design patterns that focus on the interactions and
communication between objects. They help define how objects collaborate and distribute
responsibility among them, making it easier to manage complex control flow and communication in a
system.

Types of Behavioral Design Patterns

There are mainly 10 types of Behavioral design patterns:

1. Chain Of Responsibility Method Design Pattern

The Chain of Responsibility design pattern allows an object to pass a request along a chain of
handlers. Each handler in the chain decides either to process the request or to pass it along the chain
to the next handler. Below is when to use this method:
• Use them when your objects need to communicate in complicated ways.

• Choose them when you want to easily change how things behave while the program is
running.

2. Command Method Design Pattern

The Command Design Pattern turns a request into a stand-alone object called a command. With the
help of this pattern, you can capture each component of a request, including the object that owns
the method, the parameters for the method, and the method itself. Below is when to use this
method:

• In order to separate the requester making the request (the sender) from the object executing
it, use the Command Pattern.

• If you need to support undo and redo operations in your application, the Command Pattern
is a good fit.

3. Interpreter Method Design Pattern

The Interpreter design pattern defines a way to interpret and evaluate language grammar or
expressions. It provides a mechanism to evaluate sentences in a language by representing their
grammar as a set of classes. Below is when to use this method:

• If you need to interpret and execute expressions or commands in a domain-specific language


(DSL).

• If your application frequently requires the addition of new operations or commands.

4. Mediator Method Design Pattern

Mediator Design Pattern defines an object that enacapsulates how a set of objects interact. Mediator
promotes loose coupling by keeping objects from referring to each other explicity, and it vary from
their interaction independently. Below is when to use this method:

• When your system involves a set of objects that need to communicate with each other in a
complex manner

• When you need a centralized mechanism to coordinate and control the interactions between
objects, ensuring a more organized and maintainable system.

5. Memento Method Design Patterns

The Memento design pattern is used to capture and restore an object’s internal state without
violating encapsulation. It allows you to save and restore the state of an object to a previous state,
providing the ability to undo or roll back changes made to the object. Below is when to use this
method:

• When you need to save the state of an object at various points in time to support features
like versioning or checkpoints.

• When you need to rollback changes to an object’s state in case of errors or exceptions, such
as in database transactions.

6. Observer Method Design Pattern


Observer method or Observer design pattern also known as dependents and publish-subscribe. It
define a one to many dependancy between objects so that when one objects so that when one
object change state, all its dependents are notified and updated automatically. Below is when to use
this method:

• When a change to one object requires 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.

7. State Method Design Pattern

State method or State Design Pattern also known as objects for states, it allow an object to alter its
behaviour when its internal state changes. Below is when to use this method:

• When conditional statements (if-else or switch-case) become extensive and complex within
your object.

• If your object transitions between states frequently, the State pattern provides a clear
mechanism for managing these transitions and their associated actions.

8. Strategy Method Design Pattern

Strategy method or Strategy Design Pattern also known as Policy, it define a family of algorithm,
encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary
independently from clients that use it. Below is when to use this method:

• When you have multiple algorithms that can be used interchangeably based on different
contexts, such as sorting algorithms (bubble sort, merge sort, quick sort), searching
algorithms, compression algorithms, etc.

• When you need to dynamically select and switch between different algorithms at runtime
based on user preferences, configuration settings, or system states.

9. Template Method Design Pattern

Template method or Template Design Pattern, it define the skeleton of an algorithm in an operation,
deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an
algorithm without changing the algorithm's structure. Below is when to use this method:

• If you have similar tasks or processes that need to be performed in different contexts.

• It’s beneficial when you want to enforce a specific structure or sequence of steps in an
algorithm while allowing for flexibility in certain parts.

10. Visitor Method Design Pattern

The Visitor design pattern allows you to add new operations to a group of related classes without
modifying their structures. It is particularly useful when you have a stable set of classes but need to
perform various operations on them, making it easy to extend functionality without altering the
existing codebase. Below is when to use this method:

• When you have a set of related classes and need to perform different operations on them,
the Visitor pattern allows you to add new operations without changing the classes.
• Use it when your object structure is unlikely to change frequently, but you anticipate needing
to add new operations over time.

You might also like