Aula 9 - Design Patterns
Aula 9 - Design Patterns
Lesson 9
Design Patterns
1
Introduction to Design Patterns in Object-Oriented Programming
2
Why Design Patterns?
3
The Concept of Design Patterns
• The concept of design patterns did not necessarily start with the need for reusable
software.
• The seminal work on design patterns is about constructing buildings and cities.
• Christopher Alexander noted in A Pattern Language: Towns, Buildings,
Construction:
“Each pattern describes a problem that occurs over and over again in our environ-
ment, and then describes the core of the solution to that problem in such a way
that you can use the solution a million times over, without ever doing it the same
way twice.”
4
The Four Elements of a Pattern
• Pattern Name: A handle to describe a design problem, its solutions, and consequences
in just a word or two.
• Naming a pattern increases our design vocabulary and lets us design at a higher level of
abstraction.
• Having this vocabulary allows easier communication with colleagues, in documentation, and
even for personal use.
• Good pattern names make it easier to discuss designs and their tradeoffs with others.
• Finding suitable names has been one of the hardest parts of developing our catalog.
5
The Four Elements of a Pattern
• The Problem: Describes when to apply the pattern and provides context.
• Explains the design problem, such as how to represent algorithms as objects.
• May identify class or object structures that indicate inflexible design.
• Sometimes includes conditions that must be met before the pattern is applicable.
6
The Four Elements of a Pattern
• The Solution: Describes the elements that constitute the design, including their
relationships, responsibilities, and collaborations.
• Doesn’t specify a particular concrete design or implementation because a pattern serves as a
flexible template.
• Provides an abstract description of a design problem and how a general arrangement of
elements can solve it.
• The arrangement typically includes classes and objects to form a generalized solution.
7
The Four Elements of a Pattern
8
Smalltalk’s Model/View/Controller
9
Historical Perspective on MVC
10
MVC Components Defined by Design Patterns
11
MVC: Core Components & Responsibilities
MVC divides application concerns into three key roles:
Controller: Intermediary
• Handles user input received from View.
• Updates Model based on this input.
• May select or update View after Model changes.
• Ex: Responds to ”Add Task” button click.
12
Advantages and Drawbacks of MVC
• Following MVC concept and separate the user interface, business logic, and data:
• Your system will be more flexible and robust.
• Changing the GUI won’t affect business logic or data.
• Adjusting business logic won’t require GUI changes.
• Modifying how data is stored won’t affect GUI or business logic, assuming interfaces between
the three don’t change.
MVC Example
Consider a GUI with a list of phone numbers as an example involving a list box. The list
box is the view, the phone list is the model, and the controller is the logic binding the list
box to the phone list.
MVC Drawbacks
Although the MVC is a great design, it can become complex due to the required upfront
design attention. Object-oriented design has the challenge of balancing good and
cumbersome design. The key question is how much complexity should be included. 13
MVC: Component Interaction Flow
Components collaborate in a cycle to process user input and update views:
Interaction Steps:
1. User interacts with View. User
2. View notifies Controller of the user
1
⃝ Interacts
action.
3. Controller updates the Model
Forwards Action
View
(data/logic).
4. Model (if state changed) notifies
observing View(s).
Controller
⃝
⃝4 Notifies /
2
5. View(s) query Model and refresh their 5 View Updates
⃝ 3
⃝ Updates
display.
Model
View (TaskDisplay)
• UI: Displays tasks, input field, ”Add” button, checkboxes.
• Refresh: Updates its display when the Model changes.
• Input: Forwards user actions (e.g., ”Add” click, checkbox toggle) to Controller.
Controller (TaskActionHandler)
• Handles Events: Listens to UI events from the View.
• Updates Model: E.g., on ”Add” click, calls ‘Model.addTask(textFromView)‘.
• Coordinates (loosely): Often relies on Model’s notification mechanism to update View.
16
MVC: Leveraging Object-Oriented Principles
18
Design Patterns: Categorization and Historical Context
19
Categories of Patterns
• Language Irrelevance:
• The specific programming language is irrelevant, as the book is focused on design.
• Patterns can be implemented in any language.
• Three Categories of Patterns:
• Creational Patterns: Create objects for you, providing flexibility in object instantiation.
• Structural Patterns: Compose groups of objects into larger structures like complex UIs or
accounting data.
• Behavioral Patterns: Define communication and flow between objects in complex programs.
20
Creational Patterns
21
Creational Patterns Categories
Scope: This chapter aims to describe what a design pattern is rather than cover each
pattern in the GoF book.
Example Pattern: We’ll focus on three patterns: Singleton, Factory Method, Builder.
22
Creational Patterns
Singleton
23
The Singleton Design Pattern
Definition: The Singleton pattern is a creational pattern that ensures a class has only a
single instance and provides a global point of access to that instance.
• Purpose: Regulates object creation to one instance per class.
• Example Use Case:
• A website counter object tracks the hits on a page.
• The counter object should not be re-instantiated each time a page is loaded.
• A single instance is created with the first hit and reused to increment the count afterward.
25
Singleton Pattern Code Example
Access and Instance Control:
• Any class needing the singleton instance should use the getInstance() method.
• The constructor controls object creation like any OO design.
• The getInstance() method handles instantiation:
• Checks if the singleton instance is null.
• Instantiates a new object if required.
• Returns the singleton instance.
• Each reference in the application pointing to the singleton must be managed properly.
• Multiple references can coexist but should refer to the same singleton instance.
public class Singleton {
p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g s ) {
Counter counter1 = Counter . g e t I n s t a n c e () ;
System . o u t . p r i n t l n ( ” C o u n t e r : ” + c o u n t e r 1 . g e t C o u n t e r ( ) ) ;
Counter counter2 = Counter . g e t I n s t a n c e () ;
System . o u t . p r i n t l n ( ” C o u n t e r : ” + c o u n t e r 2 . g e t C o u n t e r ( ) ) ;
}
}
Explanation:
• counter1 increments twice before displaying its value.
• counter2 then increments once and displays its value.
• Both references output the same, cumulative count, proving that they’re pointing to the
same instance. 28
Singleton: Advantages and Disadvantages
Advantages Disadvantages
• Ensured Unique Instance: Guarantees only one • Global State: Can make code harder to test and
object of its kind. reason about due to widespread dependencies on a
• Global Access Point: Provides a well-known way to single instance.
access this instance. • Testability Issues: Difficult to mock or replace the
• Lazy Initialization (Optional): The instance can be singleton instance in unit tests.
created only when first needed (in some • Violates Single Responsibility Principle (SRP): The
implementations). class often manages its own lifecycle *and* its
• Resource Control: Useful for managing shared primary business logic.
resources like configurations, loggers, or hardware • Inflexibility: Can be hard to adapt if multiple
interfaces. instances are needed later.
Consider alternatives like Dependency Injection for managing shared instances, especially in complex
applications.
29
Singleton: Core Object-Oriented Mechanisms
Factory Method
31
Factory Method: Concept, Intent & UML
Definition: A creational design pattern that provides an interface for creating objects in a
superclass, but allows subclasses to alter the type of objects that will be created.
Advantages Disadvantages
• Loose Coupling: The client code in the Creator (or the • Increased Number of Classes: Can lead to a
client using the Creator) works with the ‘Product‘ larger class hierarchy, as each
interface and is unaware of concrete ‘Product‘ classes. ‘ConcreteProduct‘ often requires a dedicated
• Extensibility (Open/Closed Principle): New product ‘ConcreteCreator‘ subclass.
types can be introduced by adding new • Subclassing Requirement: The pattern relies
‘ConcreteProduct‘ classes and corresponding on creating subclasses for the ‘Creator‘ class
‘ConcreteCreator‘ subclasses without modifying existing to implement different factory methods,
Creator logic or client code. which might be an overhead.
• Single Responsibility Principle (SRP): Moves the • Complexity for Simple Cases: If only a few
responsibility of product creation into specific factory product types exist and they don’t change
methods within concrete creator classes, isolating this often, a simpler approach (like a Simple
logic. Factory) might be sufficient.
• Flexibility for Subclasses: Subclasses have full control
over the type of product created.
34
Factory Method: Core Object-Oriented Mechanisms
Builder
36
Builder: Concept, Intent UML
Advantages Disadvantages
• Step-by-Step Construction: Allows creating • Increased Complexity: Requires creating several
objects with fine-grained control over the assembly new classes: the Builder interface, one or more
process. Parts can be built incrementally. ConcreteBuilders, and potentially a Director.
• Avoids Telescoping Constructors: Leads to • Mutability During Construction: The object
cleaner code when an object has many optional being built is often mutable and in an incomplete
parameters or configurations. state until the final ‘getResult()‘ (or ‘build()‘)
• Reusable Construction Logic: The same method is called. This needs to be managed
construction process (managed by a Director) can carefully.
be used to create different representations of the • Verbosity: Can be more verbose for simple objects
Product by using different ConcreteBuilders. where direct construction is straightforward.
• Single Responsibility Principle (SRP): Isolates • Director’s Role: If a Director is not used, the
complex construction logic from the Product’s client code becomes responsible for orchestrating
business logic and from the client code. the build steps, which might re-introduce
complexity to the client.
39
Builder: Core Object-Oriented Mechanisms
41
Structural Design Patterns
Purpose of Structural Patterns:
• Structural patterns are used to create larger structures from groups of objects.
• These patterns help separate interfaces from implementations.
Members of the Structural Category: Adapter Pattern:
• Adapter • One of the most important design patterns.
• Bridge • Effectively separates the implementation
from the interface.
• Composite
• Facilitates compatibility between different
• Decorator
interfaces.
• Façade
• Flyweight
• Proxy
42
Structural Patterns
Adapter
43
Adapter: Concept, Intent & UML
A structural design pattern that allows objects with incompatible interfaces to collaborate. It acts as a bridge
or wrapper between two incompatible interfaces, making them work together. Also Known As: Wrapper.
Advantages Disadvantages
• Interoperability: Allows classes with • Increased Complexity: Introduces an additional
incompatible interfaces to seamlessly work class (the Adapter), which adds a layer of
together. indirection to the system.
• Reusability of Existing Code: Enables the use • Overhead (Class Adapter): Tightly couples the
of existing (Adaptee) classes without needing to Adapter to a specific Adaptee class
modify their source code. implementation, making it less flexible.
• Flexibility (Object Adapter): An Adapter can • Potential for ”Fat” Adapters: If the Target
work with many Adaptees (the Adaptee instance interface is extensive, the Adapter might become
can be passed at runtime). complex with numerous forwarding methods and
• Single Responsibility Principle (SRP): The translation logic.
responsibility of interface conversion is • Translation Effort: The logic to translate data
encapsulated within the Adapter class. or calls between interfaces can sometimes be
non-trivial.
46
Adapter: Core Object-Oriented Mechanisms
Interfaces & Polymorphism
• Target Interface Implementation: The Adapter class implements the ‘Target‘ interface, which is the
specific interface the client code expects and is designed to work with.
• Polymorphic Usage: This allows clients to interact with the Adapter object polymorphically through the
‘Target‘ interface. The client treats the Adapter just like any other object that conforms to the ‘Target‘
interface, remaining unaware of the underlying ‘Adaptee‘.
• Delegation of Requests: When a client calls a method on the Adapter (via the ‘Target‘ interface), the
Adapter delegates this request by translating it into one or more calls on the methods of the wrapped
‘Adaptee‘ instance.
47
Structural Patterns
Decorator
48
Decorator: Concept, Intent & UML
Definition: A structural design pattern that allows behavior to be added to individual objects dynamically,
without affecting the behavior of other objects from the same class. Also Known As: Wrapper.
Advantages Disadvantages
• Flexibility for Adding Responsibilities: Behaviors can • Many Small Objects: Can lead to a system with a
be added to (or removed from) objects dynamically large number of small decorator objects, which might
at runtime by adding or removing decorators. be slightly harder to manage or understand.
• Avoids Feature Bloat in Superclasses: Functionality • Complexity in Understanding Decorator Chain: The
is added by small, composable decorator objects, structure of deeply nested decorators can sometimes
rather than creating many subclasses. be complex to configure correctly or debug, as
• Open/Closed Principle Adherence: New decorators behavior is distributed among many small classes.
can be introduced without modifying existing • Tight Coupling to Component Interface: Decorators
component or decorator classes. are tightly coupled to the specific ‘Component‘
• Composable Functionality: Multiple decorators can interface they decorate. A significant change in this
be nested (stacked) to combine several layers of interface can require changes in all concrete
functionality for a single component. decorators.
• Interface Consistency: Decorated objects retain the • Object Identity Issues: A decorated object is not
same interface as the original component, making identical to the original object (e.g.,
them transparent to clients that expect the original ‘decoratorInstance != originalInstance‘). This might
component’s type. be an issue for client code that relies on strict object
identity (‘==‘ checks). 51
Decorator: Core Object-Oriented Mechanisms
Shared Interface & Polymorphism (‘Component‘)
• Both the original objects (‘ConcreteComponent‘) and all ‘Decorator‘ classes implement a common ‘Component‘
interface (or extend an abstract class).
• This ensures that clients can treat both original and decorated objects polymorphically through the same interface,
making decorators transparent to client code.
Facade
53
Facade: Concept, Intent & UML
Definition: A structural design pattern that provides a simplified, unified interface to a complex subsystem of classes,
a library, or a framework. It effectively hides the system’s underlying complexity from the client.
Advantages Disadvantages
• Simplified Interface: Provides a much simpler, • Potential ”God Object”: The Facade itself can
higher-level way to interact with a complex become a large and complex class if it tries to
subsystem. expose too much functionality from the subsystem
• Decoupling Clients from Subsystem: Clients are or becomes coupled to too many subsystem
shielded from the internal complexity and changes components.
within the subsystem. • May Hide Useful Features (if not designed
• Improved Readability & Usability: Client code well): While simplifying, a Facade might
becomes cleaner and more focused on its primary inadvertently hide lower-level features or flexibility.
tasks, rather than on managing the intricacies of • Doesn’t Fix Poor Subsystem Design: A Facade
subsystem interactions. provides a simpler interface but does not inherently
• Layering and Reduced Dependencies: Promotes improve a poorly designed underlying subsystem.
better software layering by providing a controlled • Single Point of Entry Concerns: If the Facade is
entry point to a subsystem, thus reducing direct the only way to access the subsystem, it can
dependencies from clients other subsystem classes. become a bottleneck or a single point of failure.
56
Facade: Core Object-Oriented Mechanisms
Encapsulation & Abstraction
• Encapsulation of Subsystem Complexity: The Facade class effectively hides the intricate details, internal
structure, and interdependencies of the numerous classes within a subsystem from the client.
• Simplified Abstract Interface: The Facade provides a single, unified, and higher-level interface (an abstraction) to
the subsystem.
58
Behavioral Patterns: Iterator Example
Behavioral Patterns Categ: Iterator Pattern Overview:
• Chain of Responsibility • Provides a way to sequentially access elements of a collection
• Command without exposing its internal structure.
• Implemented by several programming languages, offering a
• Interpreter
consistent way to navigate through data structures.
• Iterator
• Used to iterate through lists, arrays, and other collections.
• Mediator
Key Features:
• Memento
• Separates traversal logic from collection logic, providing
• Observer flexibility.
• State • Supports different types of traversal, like forward or backward
• Strategy iteration.
Iterator
60
The Iterator Design Pattern
• The iterate() method uses an enhanced for loop to traverse and print elements.
• The iterator pattern makes this traversal easy and secure.
61
Java Iterator Implementation
public class Iterator {
p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) {
// I n s t a n t i a t e an A r r a y L i s t
A r r a y L i s t <S t r i n g > names = new A r r a y L i s t <>() ;
// Add v a l u e s t o t h e A r r a y L i s t
names . add ( ” J o e ” ) ;
names . add ( ” Mary ” ) ;
names . add ( ”Bob” ) ;
names . add ( ” Sue ” ) ;
// Now i t e r a t e t h r o u g h t h e names
System . o u t . p r i n t l n ( ” Names : ” ) ;
i t e r a t e ( names ) ;
}
p r i v a t e s t a t i c v o i d i t e r a t e ( A r r a y L i s t <S t r i n g > a r l ) {
for ( String listItem : arl ) {
System . o u t . p r i n t l n ( l i s t I t e m . t o S t r i n g ( ) ) ;
}
}
}
Observer
63
Observer: Concept, Intent & UML
Typical UML Structure:
Intent & Problem Solved
• Define a one-to-many dependency between objects so that when
one object (Subject) changes state, all its dependents (Observers)
are notified and updated automatically.
• Keep objects synchronized without creating tight interdependencies.
• Allow an object to notify an open-ended number of other objects.
Advantages Disadvantages
• Loose Coupling: The Subject and its Observers are • Unexpected Updates / Update Storm: If Observers,
loosely coupled. The Subject only knows that its upon receiving an update, trigger further state changes
observers implement the ‘Observer‘ interface. Observers in the Subject (or other observed objects), it can lead to
can be added or removed without affecting the Subject a cascade of updates, potentially infinite loops if not
or other Observers. designed carefully.
• Dynamic Relationships: The relationship between • Order of Notification Not Guaranteed: The sequence
Subjects and Observers can be established and modified in which Observers are notified is often not defined or
dynamically at runtime. guaranteed.
• Broadcast Communication: The Subject can notify any • Dangling References / Memory Leaks: If Observers are
number of registered Observers simultaneously without not explicitly detached from the Subject when they are
needing to know their concrete types or even how many no longer needed, it can lead to memory leaks.
there are. • Performance Issues with Many Observers: Notifying a
• Open/Closed Principle Adherence: New types of very large number of observers sequentially can
Observers can be introduced without modifying the sometimes impact performance.
Subject’s existing code. • Data Transmission Strategy (Push vs. Pull): Deciding
• Reusability: Both Subject and Observer classes can whether the Subject should push all relevant state data
often be reused independently in different contexts. with the notification or if Observers should pull data. 66
Behavioral Patterns
Strategy
67
Strategy: Concept, Intent & UML
Definition: A behavioral design pattern that defines a family of algorithms, encapsulates each algorithm, and
makes them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.
Advantages Disadvantages
• Interchangeable Algorithms: Families of related • Increased Number of Objects: Can lead to a
algorithms can be defined and easily swapped at proliferation of small strategy objects if there are
runtime. This provides high flexibility. many variations of algorithms, potentially
• Open/Closed Principle Adherence: New increasing the overall object count in the system.
strategies (algorithms) can be added without • Client Awareness of Strategies: Clients often
modifying the ‘Context‘ class or other existing need to be aware of the different available
strategy classes. strategies to choose and configure the ‘Context‘
• Reduces Conditional Logic: Eliminates complex appropriately. (This can sometimes be mitigated by
‘if-else‘ or ‘switch‘ statements for selecting different using a Factory to create/select strategies for the
behaviors within the ‘Context‘, leading to cleaner client).
code. • Communication Overhead: There’s a minor
• Isolation of Algorithm Details: Specific algorithm overhead due to the delegation of work from the
implementations are encapsulated within their own ‘Context‘ to the ‘Strategy‘ object (an extra method
‘ConcreteStrategy‘ classes, improving code call). This is usually negligible in most applications.
70
organization, readability, and testability.
Antipatterns
71
Antipatterns
Definition:
• Collections of past negative experiences where design solutions went wrong.
• Serve as practices to avoid, opposite to proactive design patterns.
Antipattern Characteristics:
• Most software projects face failure due to poor design decisions.
• Highlight problematic approaches, often leading to outright project cancellations.
• Derived from reactionary, flawed experiences in software development.
Facets of Antipatterns (Koenig, 1995):
• Bad Solutions: Describe ineffective approaches that lead to adverse situations.
• Recovery Paths: Outline how to escape these situations and reach a better solution.
Reference: Johnny Johnson’s article, “Creating Chaos,” discusses the prevalence of project
cancellations. 72
The Utility of Antipatterns
Why Antipatterns Are Useful:
• They help identify root causes of design issues that have already occurred.
• The concept of root-cause analysis allows the examination of failed design patterns.
• Antipatterns emerge from the failure of previous solutions, providing valuable hindsight.
Scott Ambler’s Reuse Patterns and Antipatterns:
• Robust Artifact Pattern:
• Well-documented and thoroughly tested item that meets general needs.
• Multiple examples show how to work with it.
• Easy to understand and work with, making it more reusable.
• Reuseless Artifact Antipattern:
• An artifact mistakenly declared reusable but never actually reused.
• Requires reworking to become a robust artifact that meets wider requirements.
74
Chapter Summary
• Design patterns are rooted in everyday life and should shape how we think about
object-oriented design.
• Solutions are often derived from real-life situations, providing practical relevance.
Further Exploration:
• This chapter covered design patterns briefly but highlighted their importance.
• To delve deeper into design patterns and their practical applications, consult the
recommended books listed at the chapter’s end.
75
MC322 - Object Oriented Programming
Lesson 9
Design Patterns