Introduction to Design Patterns (PART 2)

NJI Darlington
7 min readMar 11, 2024

--

Introduction to Design Patterns Part 1

Introduction to Design Patterns Part 3

In our previous session, we talked about what design patterns are and gave an introduction to the Creational approach and its design patterns.
In this session, we will be talking about the second approach which is the structural patterns, and describe the patterns available in this

Design patterns solve many of the day-to-day problems object-oriented designers face in many different ways. An example of such a problem is an Object-oriented program object and state. An object packages both data and the procedures that operate on that data. The procedures are typically called methods or operations. An object performs an operation when it receives a request (or message) from a client.

2. Structural Patterns

Structural patterns are concerned with how classes and objects are composed to form larger structures. Structural class patterns use inheritance to compose interfaces or implementations. As a simple example, consider how multiple inheritance mixes two or more classes into one. The result is a class that combines the properties of its parent classes.

Rather than composing interfaces or implementations, structural object 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

A. Adapter Design pattern

Convert the interface of a class into another interface clients expect. The adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

Use the Adapter pattern when

You want to use an existing class, and its interface does not match the one you need.
You want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don’t necessarily have compatible interfaces.
(object adapter only) you need to use several existing subclasses, but it’s impractical to adapt their interface by subclassing every one. An object adapter can adapt the interface of its parent class.

A class adapter uses multiple inheritance to adapt one interface to another
An object adapter relies on object composition

B. Bridge Pattern (aka Handle/Body)

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

We can use the Bridge Pattern when:
1.
you want to avoid a permanent binding between an abstraction and its implementation
2. both the abstractions and their implementations should be extensible by subclassing
3. changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled.
4. you want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client

Structure of bridge pattern

C. Composite Design Pattern

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly

It enables the creation of tree-like structures where both leaf nodes (individual objects) and composite nodes (collections of objects) share a common interface. Clients can interact with these nodes without distinguishing between them, simplifying the code and providing a unified approach to working with complex hierarchies. This pattern is particularly useful when dealing with hierarchical structures of objects, allowing for the creation of versatile and recursive compositions that seamlessly integrate individual elements and their aggregations.

Use the Composite pattern when
1. You want to represent part-whole hierarchies of objects.
2. You want clients to be able to ignore the difference between compositions of objects and individual objects. Clients will treat all objects in the composite structure uniformly

Structure of composite design pattern
  1. Leaf (Rectangle, Line, Text, etc.)
    represents leaf objects in the composition. A leaf has no children.
    defines behavior for primitive objects in the composition.
  2. Composite (Picture)
    defines behavior for components having children. ❍ stores child components.
    implements child-related operations in the Component interface.
  3. Client
    manipulates objects in the composition through the Component interface

D. Decorator (aka Wrapper)

It allows us to dynamically add functionality and behavior to an object without affecting the behavior of other existing objects within the same class.
We use inheritance to extend the behavior of the class. This takes place at compile-time, and all the instances of that class get the extended behavior.

Use Decorator
To add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects.
For responsibilities that can be withdrawn.
When extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination

Structure of decorator design pattern

The Decorator pattern has at least two key benefits and two liabilities:
1. More flexibility than static inheritance. The Decorator pattern provides a more flexible way to add responsibilities to objects than can be had with static (multiple) inheritance
2. A decorator and its component aren’t identical. A decorator acts as a transparent enclosure. But from an object identity point of view, a decorated component is not identical to the component itself
3. A design that uses Decorator often results in systems composed of lots of little objects that all look alike

E. Facade Design Pattern

Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

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

Facade subsystem of classes

The Facade pattern offers the following benefits:

  1. It shields clients from subsystem components, thereby reducing the number of objects that clients deal with and making the subsystem easier to use.
  2. It doesn’t prevent applications from using subsystem classes if they need to. Thus you can choose between ease of use and generality
  3. It promotes weak coupling between the subsystem and its clients.

However, facade creates issues in implementing such as
1. Reducting client-subsystem coupling
2. Public versus private subsystem classes

F Flyweight Pattern

Use sharing to support large numbers of fine-grained objects efficiently

It is a structural pattern that aims to minimize memory usage or computational expenses by sharing as much as possible with related objects. It achieves this by separating an object’s intrinsic state (shared and immutable) from its extrinsic state (context-dependent and variable). The pattern enables a single instance of the shared intrinsic state to be reused across multiple objects, reducing the overall memory footprint. This is particularly beneficial when dealing with a large number of similar objects, as it optimizes performance and resource usage by promoting the sharing of common, unchanging information.

G. Proxy Design Pattern (aka Surrogate)

Provide a surrogate or placeholder for another object to control access to it

This surrogate object, known as the proxy, acts as an intermediary, allowing or restricting access to the real object based on certain conditions. The proxy pattern is useful in scenarios where you want to add an extra layer of control, such as lazy loading (loading an object only when it is needed), access control, logging, or monitoring, without directly modifying the behavior of the real object. The proxy and the real object typically share a common interface, ensuring that clients can interact with both interchangeably. This pattern enhances modularity and flexibility in managing object interactions while maintaining a level of indirection between clients and the actual implementation.

Structure of Proxy design pattern

Let’s End here for today.
Next time we will dive into the last category of patterns which are the Structural Patterns

Thank you for reading till the end. Please like and follow

Introduction to Design Patterns Part 3

You can get to me directly if you have any questions

Twitter: https://x.com/kdaprov

YouTube: https://youtube.com/@rising_tide

Email: darlingtonkimbi@gmail.com

LinkedIn: https://www.linkedin.com/in/kimbi-darlington-a867691b1/

--

--

NJI Darlington

I write content about software architecture, mobile design and algorithm. YouTube: @rising_tide