Principles and patterns of object oriented design. answering the most common questions faced when designing a system, e.g., how to model the domain? how to prepare the code for modification? how to handle an object's life cycle?
3. What to ask when designing
0 Which class should a responsibility be assigned to?
0 How to organize the system’s responsibilities?
0 How to model the domain?
0 How to handle an object’s lifecycle?
0 How to prepare the code for modification?
3
5. 0Information Expert [GRASP]
0 A responsibility dealing with X should be
assigned to the object holding X
0Single Responsibility Principle [SOLID]
0 Each class should have one and only one
responsibility
0Interface Segregation [SOLID]
0 Favour small specific interfaces so clients don’t
depend on interfaces they don’t use
5
6. Corollary of Information Expert
Getters and setters are Evil
(don’t ask for data, delegate as much as possible)
6
10. Layers pattern
0 You are designing a system whose dominant
characteristic is a mix of low- and high-level issues,
where high-level operations rely on the lower-level
ones.
0 Therefore
0 Structure your system into an appropriate number of
layers and place them on top of each other, each
providing a specific level of abstraction.
10
GoF
12. 0Low coupling [GRASP]
0 Keep coupling of elements to a minimum.
Avoid circular dependencies.
0High Cohesion [GRASP]
0 Keep related elements close together
0Indirection [GRASP]
0 Avoid tight coupling by creating an
indirection layer
13
13. Façade
0 Work is actually performed by a series of subsystem
but this level of complexity must be hidden from the
client
0 Therefore
0 Create a facade object offering a simpler, high level
interface which delegates work in the actual subsystems
14
GoF
14. Controller
0 You need to coordinate application activity - the
interactions of a use case with the UI or external
systems
0 Therefore
0 Assign the responsibility of use case coordination to a
dedicated use case controller which exposes a business
API (application layer) and performs no business logic
but delegates to the right domain objects instead
15
GRASP
16. Look at your domain model’s
ubiquitous language
17
17. Entity
0 Some objects in the domain have a thread of
continuity which we need to track by its identity.
0 Therefore
0 Model objects in the real world as entities, assigning
each object one or more identities. Equality of
references is done comparing the identity of the object.
18
DDD
18. Entity: example
Class Account{
public Account(AccountNumber accn) {…}
public boolean equals(Object other) {
if (other==this) return true;
if (!(other instanceof Account)) return false;
return (this.getID() == (Account)other.getID());
}
public void withdraw(Money amount) {
if (hasEnoughBalance(amount)
|| overdraftAllowed(amount)) {
// business logic for withdrawing
// and updating balances
}
}
}
19
19. Value Object
0 Not everything needs an identity; some things matter
for the value of its attributes.
0 Therefore
0 Create immutable objects whose equality is
determined by the equality of its attributes.
20
DDD
20. Value object: example
Class Balance{
public Balance(Money amount, Calendar asOf) {…}
// getters (but no setters)
public Money amount() {…}
public Calendar asOf() {…}
// creates a new Balance object
// keeping this and the other object unchanged
public Balance add(Money some) {…}
public Balance add(Money some, Calendar effectiveOn) {…}
public Balance subtract(Money some) {…}
...
public boolean equals(Object other) {…}
}
21
21. Service
0 Some business operations are not naturally placed
in a certain domain object
0 Therefore
0 Create a service object that handles only that operation
and coordinates the necessary domain objects.
23
DDD
22. Service: example
class TransferService {
public void transfer(Money amount,
Account from, Account to) {
if (isAllowedToTransfer(from, amount, to) {
from.withdraw(amount);
to.deposit(amount);
}
}
private boolean isAllowedToTransfer(Account from,
Money amount,
Account to) {
// rules specific to account transfers
// (e.g., maximum allowed amount to transfer for
// international account)
}
}
24
24. A pragmatic design
26
• Remove
unnecessary
associations
• Force traversal
direction of
bidirectional
associations
• Reduce
cardinality by
qualification of
the association
we are still left
with a tangle of
interconnected
objects...
25. Aggregate
0 Some objects are closely related together and we need
to control the scope of data changes so that invariants
are enforced
0 Therefore
0 Keep related objects with frequent changes bundled in
an aggregate
0 control access to the “inner” objects thru one single
“root” object
27
DDD
26. A more pragmatic design
28
Legend:
• Account
aggregate
• Customer
aggregate
Address is a value
object so it can be
freely shared among
several aggregates
28. Object’s lifecycle
1. An object is created
2. The object is used
3. It must be persisted for later use
4. Later, the object is reconstructed from persistence
5. It is used (provably changed)
6. It is stored back again for later use
7. …
30
30. Factories
0 Creating a (large) object might be a complex task
and/or the client must be decoupled from the actual
type of the created object.
0 Therefore
0 Place construction logic in a dedicated factory which
encapsulates object creation for all clients.
32
DDD
31. 0 Creator [GRASP]
0 Assign class A creation responsibility to the class which
either (1) contains A’s instances; or (2) holds the data
for initializing an A’s instance
0 Factory Method [GoF]
0 A class method that simplifies the creation of different
implementations of the same interface
0 Simple Factory [GoF]
0 A class made up of only factory methods
0 Abstract Factory [GoF]
0 Handles the creation of related or dependent product
families
33
32. Repository
0 Client code needs to obtain a reference to an object in
order to use it (sometimes, the desired object needs to
be reconstructed from persistence). After using it the
client wants the object to be persisted again.
0 Therefore
0 Encapsulate the logic needed for obtaining object
references in a Repository. The repository handles all
the persistence logic and abstracts the client code from
such details.
34
DDD
36. Protected Variation
0 You need to design objects, components or systems so
that variations in those elements don’t impact other
elements
0 Therefore
0 Identify points of predicted variation and create a stable
interface around them.
38
GRASP
37. 0Open/Close Principle [SOLID]
0 A class should be open for extension and
adaption and closed for modification
0Dependency Inversion Principle [SOLID]
0 Clients should depend on abstractions, not
concretions. I.e., program to an interface not
a realization.
39
38. 0Polymorphism [GRASP]
0 When behaviour varies depending on type
0Template Method [GoF]
0 Define the skeleton of an algorithm in an
operation, deferring some steps to subclasses.
0Liskov Substitution Principle [SOLID]
0 Any method expecting A should work
properly with any object derived from A
40
39. Liskov Substitution Principle’s Corollary
Derived classes should adhere strictly to the semantics
of the contract
see also, Design by Contract:
Pre-conditions
Post-conditions
Invariants
41
40. Strategy
0 Sometimes there is a business policy (expressed in
the domain) that must be enforced but it actually may
have different variations of concrete policies
0 Therefore
0 Define a common interface for the policy and provide
different implementations decoupling the client from
the actual policy and allowing for permutation and
independent evolution.
42
GoF
41.
42. Topic Principles and patterns
Which class should a responsibility be
assigned to?
Information Expert
Single Responsibility Principle
Interface Segregation Principle
How to organize the system’s
responsibilities?
Layers
Façade
Controller
How to model the domain? Entity
Value Object
Service
Aggregate
How to handle an object’s lifecycle? Factories
Repositories
How to prepare the code for
modification?
Protected Variation
Open/Close Principle
Dependency Inversion Principle
Liskov Substitution Principle
Template Method
Strategy
44
43. References
0 Domain Driven Design. Eric Evans
0 Why getters and setters are Evil. Allan Holub.
http://www.javaworld.com/article/2073723/core-
java/why-getter-and-setter-methods-are-evil.html
0 Design Principles and Design Patterns. Robert Martin.
http://www.objectmentor.com/resources/articles/Princip
les_and_Patterns.pdf
0 Design Patterns-Elements of Reusable Object-oriented
Software, Gamma et al. (Gang of Four)
0 Applying UML and Patterns; Craig Larman; (2nd ed.); 2002.
45