May 24, 2015
Object Oriented Design is mainly about behaviour, not
structure.
2
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
Which class should a responsibility be assigned to?
4
0 Information 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
0 Interface Segregation [SOLID]
0 Favour small specific interfaces so clients don’t depend on interfaces they don’t use
5
Corollary of Information Expert
Getters and setters are Evil (don’t ask for data, delegate as much as possible)
6
Procedural thinking
7
Object thinking
8
How to organize the system’s responsibilities?
9
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
Common architecture
Source: domain driven design , Eric Evans 11
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
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
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
How to model the domain?
16
Look at your domain model’s ubiquitous language
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
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
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
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
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
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
An Example
25
N-to-M relationships
are hard
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...
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
A more pragmatic design
28
Legend: • Account
aggregate • Customer
aggregate
Address is a value object so it can be freely shared among several aggregates
How to handle an object’s lifecycle?
29
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
Separate use from construction
31
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
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
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
35
Rep
osi
tory
exa
mp
le
Repositories and layers
36
How to prepare the code for modification?
37
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
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
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
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
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
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
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/Principles_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