Dive Into Design Patterns en Demo
Dive Into Design Patterns en Demo
Dive Into Design Patterns en Demo
Dive
ve In
Intto
DE
DESSIGN
PAT TERN
TERNSS
v2021-2.28
DEMO VERSION
Table of Contents
Table of Contents .................................................................................................. 4
How to Read This Book......................................................................................... 6
INTRODUCTION TO OOP ........................................................................................ 7
Basics of OOP ........................................................................................ 8
Pillars of OOP..................................................................................... 13
Relations Between Objects............................................................ 20
INTRODUCTION TO DESIGN PATTERNS........................................................... 26
What’s a Design Pattern?................................................................ 27
Why Should I Learn Patterns?....................................................... 31
SOFTWARE DESIGN PRINCIPLES ..................................................................... 32
Features of Good Design................................................................ 33
Design Principles........................................................................................... 37
§ Encapsulate What Varies........................................................ 38
§ Program to an Interface, not an Implementation ......... 42
§ Favor Composition Over Inheritance................................. 47
SOLID Principles .............................................................................................51
§ Single Responsibility Principle ............................................ 52
§ Open/Closed Principle............................................................ 54
§ Liskov Substitution Principle................................................ 57
§ Interface Segregation Principle........................................... 64
§ Dependency Inversion Principle ......................................... 67
5 Table of Contents
Many patterns are related, so you can easily jump from topic
to topic using numerous anchors. The end of each chapter has
a list of links between the current pattern and others. If you
see the name of a pattern that you haven’t seen yet, just keep
reading—this item will appear in one of the next chapters.
Basics of OOP
Object-oriented programming is a paradigm based on the con-
cept of wrapping pieces of data, and behavior related to that
data, into special bundles called objects, which are construct-
ed from a set of “blueprints”, defined by a programmer, called
classes.
Objects, classes
Do you like cats? I hope you do because I’ll try to explain the
OOP concepts using various cat examples.
This is a UML class diagram. You’ll see a lot of such diagrams in the book.
9 Introduction to OOP / Basics of OOP
All cats also behave similarly: they breathe, eat, run, sleep and
meow. These are the class’s methods. Collectively, fields and
methods can be referenced as the members of their class.
Class hierarchies
Everything fine and dandy when we talk about one class. Nat-
urally, a real program contains more than a single class. Some
of these classes might be organized into class hierarchies. Let’s
find out what that means.
Say your neighbor has a dog called Fido. It turns out, dogs
and cats have a lot in common: name, sex, age, and color are
attributes of both dogs and cats. Dogs can breathe, sleep and
run the same way cats do. So it seems that we can define the
base Animal class that would list the common attributes and
behaviors.
UML diagram of a class hierarchy. All classes in this diagram are part of
the Animal class hierarchy.
Code reuse
Cost and time are two of the most valuable metrics when
developing any software product. Less time in development
means entering the market earlier than competitors. Lower
development costs mean more money is left for marketing and
a broader reach to potential customers.
The idea looks great on paper, but it turns out that making
existing code work in a new context usually takes extra effort.
Tight coupling between components, dependencies on con-
crete classes instead of interfaces, hardcoded operations—all
of this reduces flexibility of the code and makes it harder to
reuse it.
1
Here’s a piece of wisdom from Erich Gamma , one of the
founding fathers of design patterns, about the role of design
patterns in code reuse:
„
let you reuse design ideas and concepts independently of con-
crete code.
Extensibility
Change is the only constant thing in a programmer’s life.
• You released a video game for Windows, but now people ask
for a macOS version.
The third reason is that the goalposts move. Your client was
delighted with the current version of the application, but now
sees eleven “little” changes he’d like so it can do other things
he never mentioned in the original planning sessions. These
aren’t frivolous changes: your excellent first version has shown
him that even more is possible.
Design Principles
What is good software design? How would you measure it?
What practices would you need to follow to achieve it? How
can you make your architecture flexible, stable and easy to
understand?
Knowing this, you can divide the ship’s hull into independent
compartments that can be safely sealed to limit damage to a
single compartment. Now, if the ship hits a mine, the ship as a
whole remains afloat.
In the same way, you can isolate the parts of the program that
vary in independent modules, protecting the rest of the code
from adverse effects. As a result, you spend less time getting
the program back into working shape, implementing and test-
ing the changes. The less time you spend making changes, the
more time you have for implementing features.
39 Design Principles / Encapsulate What Varies
1 method getOrderTotal(order) is
2 total = 0
3 foreach item in order.lineItems
4 total += item.price * item.quantity
5
6 if (order.country == "US")
7 total += total * 0.07 // US sales tax
8 else if (order.country == "EU"):
9 total += total * 0.20 // European VAT
10
11 return total
BEFORE: tax calculation code is mixed with the rest of the method’s code.
1 method getOrderTotal(order) is
2 total = 0
3 foreach item in order.lineItems
4 total += item.price * item.quantity
5
6 total += total * getTaxRate(order.country)
7
8 return total
9
10 method getTaxRate(country) is
11 if (country == "US")
12 return 0.07 // US sales tax
13 else if (country == "EU")
14 return 0.20 // European VAT
15 else
16 return 0
AFTER: you can get the tax rate by calling a designated method.
Factory
Method
Provides an interface for creating objects in a superclass, but
allows subclasses to alter the type of objects that will be created.
Abstract
Factory
Lets you produce families of related objects without specifying
their concrete classes.
73 Creational Design Patterns
Builder
Lets you construct complex objects step by step. The pattern
allows you to produce different types and representations of an
object using the same construction code.
Prototype
Lets you copy existing objects without making your code depen-
dent on their classes.
Singleton
Lets you ensure that a class has only one instance, while provid-
ing a global access point to this instance.
74 Creational Design Patterns / Factory Method
FACTORY METHOD
Also known as: Virtual Constructor
Problem
Imagine that you’re creating a logistics management applica-
tion. The first version of your app can only handle transporta-
tion by trucks, so the bulk of your code lives inside the Truck
class.
After a while, your app becomes pretty popular. Each day you
receive dozens of requests from sea transportation companies
to incorporate sea logistics into the app.
Adding a new class to the program isn’t that simple if the rest of the code
is already coupled to existing classes.
Great news, right? But how about the code? At present, most of
your code is coupled to the Truck class. Adding Ships into
the app would require making changes to the entire codebase.
Moreover, if later you decide to add another type of transporta-
tion to the app, you will probably need to make all of these
changes again.
76 Creational Design Patterns / Factory Method
As a result, you will end up with pretty nasty code, riddled with
conditionals that switch the app’s behavior depending on the
class of transportation objects.
Solution
The Factory Method pattern suggests that you replace direct
object construction calls (using the new operator) with calls
to a special factory method. Don’t worry: the objects are still
created via the new operator, but it’s being called from within
the factory method. Objects returned by a factory method are
often referred to as products.
The code that uses the factory method (often called the client
code) doesn’t see a difference between the actual products
returned by various subclasses. The client treats all the prod-
ucts as abstract Transport .
78 Creational Design Patterns / Factory Method
Structure
79 Creational Design Patterns / Factory Method
You can declare the factory method as abstract to force all sub-
classes to implement their own versions of the method. As an
alternative, the base factory method can return some default
product type.
Pseudocode
This example illustrates how the Factory Method can be used
for creating cross-platform UI elements without coupling the
client code to concrete UI classes.
When the factory method comes into play, you don’t need to
rewrite the logic of the dialog for each operating system. If
we declare a factory method that produces buttons inside the
base dialog class, we can later create a dialog subclass that
returns Windows-styled buttons from the factory method. The
subclass then inherits most of the dialog’s code from the base
class, but, thanks to the factory method, can render Windows-
looking buttons on the screen.
For this pattern to work, the base dialog class must work with
abstract buttons: a base class or an interface that all concrete
buttons follow. This way the dialog’s code remains functional,
whichever type of buttons it works with.
75 method main() is
76 this
this.initialize()
77 dialog.render()
Applicability
Use the Factory Method when you don’t know beforehand the
exact types and dependencies of the objects your code should
work with.
For example, to add a new product type to the app, you’ll only
need to create a new creator subclass and override the factory
method in it.
Let’s see how that would work. Imagine that you write an
app using an open source UI framework. Your app should
have round buttons, but the framework only provides square
ones. You extend the standard Button class with a glorious
RoundButton subclass. But now you need to tell the main
a default one.
That’s a lot of code! And it must all be put into a single place
so that you don’t pollute the program with duplicate code.
How to Implement
1. Make all products follow the same interface. This interface
should declare methods that make sense in every product.
87 Creational Design Patterns / Factory Method
At this point, the code of the factory method may look pretty
ugly. It may have a large switch operator that picks which
product class to instantiate. But don’t worry, we’ll fix it soon
enough.
5. If there are too many product types and it doesn’t make sense
to create subclasses for all of them, you can reuse the control
parameter from the base class in subclasses.
6. If, after all of the extractions, the base factory method has
become empty, you can make it abstract. If there’s something
left, you can make it a default behavior of the method.
• You can use Factory Method along with Iterator to let collec-
tion subclasses return different types of iterators that are com-
patible with the collections.