Module6 - Object Oriented Design - Design Patterns
Module6 - Object Oriented Design - Design Patterns
Software Engineering
Computer Science
Academic Year 2023/2024
1
Contents
1. Introduction
• What will we learn
2. Object Oriented Design
- Design principles
- Design patterns
- Operation contract and Class diagram normalization
- Object responsibilities assignment
- Behavioral modeling. Sequence diagram and State diagram
- Software Architecture
- Components and Packages
1. Introduction
What will we learn?
OOA/D
Design
Design
Exercises
Patterns
OOA/D
Structural Behavioral
Creational
1. Introduction
• Book References
• The classification of patterns is done based primarily on how the objects get
created, how classes and objects are structured in a software application, and also
covers the way objects interact among themselves.
• It is not the aim of this course to learn about all the available patterns. But we will
show some examples of each category in the next sections.
2.2 Design Patterns
Pattern category Description
Creational patterns • They work on the basis of how objects can be created
• They isolate the details of object creation
• Code is independent of the type of object to be created
• They design the structure of objects and classes so that they can compose to
achieve larger results
• The focus is on simplifying the structure and identifying the relationship
Structural patterns between classes and objects
• They focus on class inheritance and composition
• They are concerned with the interaction among objects and responsibility of
Behavioral patterns objects
• Objects should be able to interact and still be loosely coupled
2.2 Design Patterns
GOF Patterns
2.2 Design Patterns
Behavioral patterns: Strategy
• Problem: Create a family of algorithms for a task and being able to decide which
one we chose at runtime.
• The strategy pattern is used when we have multiple algorithms for a specific task
and client decides the actual implementation to be used at runtime.
• It lets you define a family of algorithms, put each of them into a separate class,
and make their objects interchangeable.
2.2 Design Patterns
Behavioral patterns: Strategy
• The Strategy pattern allows the behavior of an object to be selected dynamically at
runtime, providing flexibility, modularity, and testability. The key characteristics:
ü It defines a family of algorithms: the pattern allows you to encapsulate multiple
algorithms or behaviors into separate classes, known as strategies.
ü It encapsulates behaviors: each strategy encapsulates a specific behavior or
algorithm, providing a clean and modular way to manage different variations.
ü It enables dynamic behavior switching: enables clients to switch between different
strategies at runtime, allowing for flexible and dynamic behavior changes.
ü It promotes object collaboration: the pattern encourages collaboration between a
context object and strategy objects, where the context delegates the execution of a
behavior to a strategy object.
2.2 Design Patterns
Strategy: UML class diagram
2.2 Design Patterns
Behavioral patterns: Strategy
Context
• The Context is a class or object that holds a
reference to a strategy object and delegates
the task to it.
• It acts as the interface between the client
and the strategy, providing a unified way to
execute the task without knowing the
details of how it’s done.
• The Context maintains a reference to a
strategy object and calls its methods to
perform the task, allowing for
interchangeable strategies to be used.
2.2 Design Patterns
Behavioral patterns: Strategy
Strategy Interface
• The Strategy Interface is an interface or abstract
class that defines a set of methods that all
concrete strategies must implement.
• It serves as a contract, ensuring that all
strategies adhere to the same set of rules and
can be used interchangeably by the Context.
• By defining a common interface, the Strategy
Interface allows for decoupling between the
Context and the concrete strategies, promoting
flexibility and modularity in the design.
2.2 Design Patterns
Behavioral patterns: Strategy
Concrete Strategies
• They are the various implementations of the
Strategy Interface. Each concrete strategy
provides a specific algorithm or behavior for
the task defined by the Strategy Interface.
• Concrete strategies encapsulate the details of
their respective algorithms and provide a
method for executing the task.
• They are interchangeable and can be selected
and configured by the client based on the
requirements of the task.
2.2 Design Patterns
Behavioral patterns: Strategy
Client
Strategy Interface
• We define first an abstract class Strategy that declares a method execute_strategy
common to all concrete strategies.
2.2 Design Patterns
Strategy: case study Trading system (in Python)
Concrete Strategies
• Implement concrete strategy classes ConcreteStrategyA and ConcreteStrategyB that
provide specific algorithm variations.
2.2 Design Patterns
Strategy: case study Trading system (in Python)
Context
• Develop a Context class that maintains a reference to one of the concrete strategies
and provides a method to execute the strategy.
2.2 Design Patterns
Strategy: case study Trading system (in Python)
Client
2.2 Design Patterns
Strategy: case study Trading system (in Python)
• The previous slides show the general case/setup of the pattern. For our trading
system, we could define specific trading algorithms as ConcreteStrategy (A and B).
2.1 Design Principles
Activity 6.2.1
Our system draws a path (using an algorithm) in a map,
according to a selected transport among three choices (bus,
car or walk). We use the design pattern shown in the next
class diagram.
Which of the following are true about this design pattern:
A: It’s a strategy behavior pattern
B: If the algorithms where in the same class, they would
be more difficult to maintain and modify
C: If the algorithms where in the same class, this would
be large and more difficult to maintain
D: If the algorithms where in the same class, it would be
more difficult to add new transports (ex taxi)
2.1 Design Principles
Activity 6.2.2
Which of the following statements are true for the next class diagram:
A: The Context class has the responsibility of creating a reference to a specific strategy.
B: The Strategy class inherits the specific algorithm from ConcreteStrategy (A and B).
C: The Strategy class works as an interface, that is shared by the different algorithms.
D: The ConcreteStrategy (A and B) class is the one actually implementing the algorithm.
2.2 Design Patterns
References
• You can learn more about Strategy Pattern (with Python examples) here:
https://youtu.be/WQ8bNdxREHU?si=pXsrl32MQB1Bhaqd
2.2 Design Patterns
Creational patterns: Factory
• Problem: Decoupling the process of creating objects from the clients that use
them.
• Using the factory pattern, a class will take the responsibility of creating objects.
2.2 Design Patterns
• A factory means: a class that is responsible for creating objects of other types.
• The class that acts as a factory has an object and its methods. The client calls this
method with some parameters; objects of desired types are created.
• So the question here really is, why do we need a factory when the client can directly
create an object? These are some benefits of using a factory:
ü The first advantage is loose coupling in which object creation can be independent of
the class implementation.
ü The client need not be aware of the class that creates the object which, in turn, is
utilized by the client. It is only necessary to know the interface, methods, and
parameters that need to be passed to create objects of the desired type. This
simplifies implementations for the client.
ü Adding another class to the factory to create objects of another type can be easily
done without the client changing the code. At a minimum, the client needs to pass
just another parameter.
2.2 Design Patterns
• This allows interfaces to create objects, but defers the decision to the
Factory method subclasses to determine the class for object creation.
## client code
if __name__ == '__main__':
ff = ForestFactory()
animal = input("Which animal should make_sound Dog or Cat?")
ff.make_sound(animal)
2.2 Design Patterns
Factory Method
• We define an interface to create objects, but instead of the factory being responsible for the
object creation, the responsibility is deferred to the subclass that decides the class to be
instantiated.
2.2 Design Patterns
Factory Method
• Consider that we would like to create profiles of different types on social networks such as
LinkedIn and Facebook for a person or company.
• Now, each of these profiles would have certain sections.
ü In LinkedIn, you would have a section on patents that an individual has filed or
publications s/he has written.
ü On Facebook, you'll see sections in an album of pictures of your recent visit to a
holiday place.
ü Additionally, in both these profiles, there'd be a common section on personal
information.
• We want to create profiles of different types with the right sections being added to that
profile.
2.2 Design Patterns
Factory Method: case study Social media profiles (in from abc import ABCMeta, abstractmethod
how a section will be. We will keep it very simple class AlbumSection(Section):
and provide an abstract method, describe(). def describe(self):
print("Album Section")
if __name__ == '__main__':
profile_type = input("Which Profile you'd like to create? [LinkedIn or FaceBook]")
profile = eval(profile_type.lower())()
print("Creating Profile..", type(profile).__name__)
print("Profile has sections --", profile.getSections())
2.2 Design Patterns
References
• You can learn more about Strategy Pattern (with Python examples) here:
https://youtu.be/s_4ZrtQs8Do?si=Bqs3nNUBMQuzsJXU
2.1 Design Principles
Activity 6.2.4
Which of the following are true about the Factory Method design pattern:
ü Suppose we are building a coffee shop application where customers can order
different types of coffee.
ü Each coffee can have various optional add-ons (toppings) such as milk, sugar,
whipped cream, etc.
ü We want to implement a system where we can dynamically add these add-ons
to a coffee order without modifying the coffee classes themselves.
• Using the decorator pattern allows us to add optional features (add-ons) to coffee
orders dynamically without altering the core coffee classes.
• This promotes code flexibility, scalability, and maintainability as new add-ons can
be easily introduced and combined with different types of coffee orders.
2.2 Design Patterns
Decorator UML diagram
1. Create an interface.
2. Create concrete classes implementing
the same interface.
3. Create an abstract decorator class
implementing the above same interface.
4. Create a concrete decorator class
extending the above abstract decorator
class.
5. Now use the concrete decorator class
created above to decorate interface
objects.
2.2 Design Patterns
• Component Interface: this is an abstract class or interface that defines the common
interface for both the concrete components and decorators. It specifies the operations
that can be performed on the objects.
• Concrete Component: these are the basic objects or classes that implement the
Component interface. They are the objects to which we want to add new behavior or
responsibilities.
• Decorator: this is an abstract class that also implements the Component interface and has
a reference to a Component object. Decorators are responsible for adding new behaviors
to the wrapped Component object.
• Concrete Decorator: These are the concrete classes that extend the Decorator class. They
add specific behaviors or responsibilities to the Component. Each Concrete Decorator can
add one or more behaviors to the Component.
2.2 Design Patterns
Decorator: coffee example (in Java)
Component interface
• This is the interface Coffee representing the component.
• It declares two methods getDescription() and getCost() which must be implemented
by concrete components and decorators.
2.2 Design Patterns
Decorator: coffee example (in Java)
Concrete Component
• PlainCoffee is a concrete class
implementing the Coffee interface.
• It provides the description and
cost of plain coffee by
implementing the
getDescription() and getCost()
methods.
2.2 Design Patterns
Decorator: coffee example (in Java)
Decorator
• CoffeeDecorator is an abstract class
implementing the Coffee interface.
• It maintains a reference to the
decorated Coffee object.
• The getDescription() and getCost()
methods are implemented to
delegate to the decorated coffee
object.
2.2 Design Patterns
Decorator: coffee example (in Java)
Concrete Decorators
• CoffeeDecorator is an abstract class
implementing the Coffee interface.
• MilkDecorator and SugarDecorator are
concrete decorators extending
CoffeeDecorator.
• They override getDescription() to add the
respective decorator description to the
decorated coffee’s description.
• They override getCost() to add the cost of
the respective decorator to the decorated
coffee’s cost.
2.2 Design Patterns
Decorator: coffee example (in Java)
2.2 Design Patterns
• Benefits of using decorator design patterns:
ü Open-Closed Principle: classes should be open for extension but closed for modification. This
means you can introduce new functionality to an existing class without changing its source code.
ü Flexibility: It allows to add or remove responsibilities (i.e., behaviors) from objects. This flexibility
makes it easy to create complex object structures with varying combinations of behaviors.
ü Reusable Code: Decorators are reusable components. You can create a library of decorator
classes and apply them to different objects and classes as needed, reducing code duplication.
ü Composition over Inheritance: unlike inheritance, that can lead to a large and les flexible class
hierarchy, the decorator uses composition. You can compose objects with decorators to achieve
the desired functionality, avoiding the drawbacks such as tight coupling and rigid hierarchies.
ü Dynamic Behavior Modification: Decorators can be applied or removed at runtime, providing
dynamic behavior modification for objects. This is particularly useful when you need to adapt an
object’s behavior based on changing requirements or user preferences.
ü Clear Code Structure: The Decorator pattern promotes a clear and structured design to
understand how different features and responsibilities are added to objects.
2.2 Design Patterns
ü The decorator design pattern can be useful in Python, but there are other better options.
ü In Python, there are more efficient ways of implementing the same solution.
ü Monkey-patching in Python refers to these dynamic (or run-time) modifications of a class or module.
In Python, we can actually change the behavior of code at run-time.
ü Not to be confused with Python decorators, which is a language feature for dynamically modifying a
function or class. Python Decorators are an example of monkey-patching.
ü Design patterns became famous in 1994 publication of GOF Design Patterns. In 2003, the Python core
developers re-used the term decorator for an unrelated feature they were adding (to Python 2.4).
2.2 Design Patterns
References
• The video explains the efficient implementation of the decorator design pattern in Python.
https://youtu.be/QH5fw9kxDQA?si=hZteiJjD5ICv0U-J
2.2 Design Patterns
Decorator: case study Game Characters abilities
• Consider a scenario in game design where different
characters possess a unique set of abilities.
• As the game evolves, we need to add new abilities.
• We’ll use game character abilities, such as
the DoubleDamageDecorator, FireballDecorator,
and InvisibilityDecorator, as examples.
• Characters can have different combinations of these
abilities at any given moment.
• We will implement the decorator design pattern to
enhance a character’s abilities. By dynamically
applying decorators, such as Double Damage and
Invisibility, to a basic character, we create a special
character with combined powers.
2.2 Design Patterns
Decorator: case study Game Characters abilities (in Python)
Component
• The Component is the base
interface that defines the core
behavior that can be enhanced.
• In our example, it represents the
game character with a basic
attack method.
2.2 Design Patterns
Decorator: case study Game Characters abilities (in Python)
Concrete Component
• Concrete Components are the basic game characters to which we can add
special abilities. In this step, we create the basic character class.
2.2 Design Patterns
Decorator: case study Game Characters abilities (in Python)
Decorator
Concrete Decorator
• Concrete Decorators are classes
that extend the Decorator
abstract class, implementing
specific behaviors.
• In this step, we create concrete
decorator classes for special
character abilities, such as
Double Damage.
2.2 Design Patterns
Decorator: case study Game Characters abilities (in Python)
Client
2.1 Design Principles
Activity 6.2.6
The UML diagram shows a design pattern for a system drawing shapes. We’re going to create a Shape
interface and concrete classes implementing the Shape interface. We will also create an abstract
decorator class ShapeDecorator implementing the Shape interface and having the Shape object as its
instance variable.
Which of the following are true: