8. The domain, SRP and Value Objects
Primitive types are not the best option to represent
domain concepts!
Favour imutability of your objects.
7
Person
«value»
Name
«value»
Address
«value»
NIF
«value»
PhoneNumber
1..*1
1 *
«value»
Email
*
12. Template Method
Define an overall
algorithm structure while
allowing for certain
operations (steps) to be
tailored for concrete
cases
11
13. Strategy
Provide different implementations of the same
algorithm and allow the client to choose which one to
use.
source: Design Patterns: Elements of Reusable Object-Oriented Software
14. Decorator
Dynamically attach additional
responsibilities to an object.
Decorators provide a flexible
alternative to subclassing for
extending functionality.
source: Design Patterns: Elements of Reusable
Object-Oriented Software
15. Visitor
Separate the algorithm from
the data structure it operates
on by creating a visitor that
traverses the desired object.
Source: http://www.oodesign.com/visitor-pattern.html
16. Liskov Substitution Principle
Subclasses should be substitutable for their base
classes.
15
The implication is:
Subclasses must abide the
same contract and invariants
of the base class, without
semantic changes.
24. Dependency Injection
Modules declare their dependencies but do not
create them explicitily
23
class Component {
NeededService svc;
Component() {
svc = new ServiceImplementation();
}
}
class Component {
NeededService svc;
Component(NeededService impl) {
svc = impl;
}
}
25. Separated Interface
Defines an interface in a
separate package from
its implementation.
source: Patterns of Enterprise Application Architecture
27. Key Principles
Consider what should be variable in your design
Program to an interface not an implementation
Keep different responsibilities apart from each
other
Favour composition instead of inheritance
29. Bibliography
• Robert C. Martin. Design Principles and Design
Patterns.
http://www.objectmentor.com/resources/articles/Princ
iples_and_Patterns.pdf
• William Durand. From STUPID to SOLID code!.
http://williamdurand.fr/2013/07/30/from-stupid-to-
solid-code/
• Allen Holub. Why extends is evil.
http://www.javaworld.com/javaworld/jw-08-2003/jw-
0801-toolbox.html
• Erich Gamma, Richard Helm, Ralph Johnson, John
Vissides. Design patterns : elements of reusable object-
oriented software. Adisson-Wesley.
Editor's Notes
Tight coupling: criar objetos concretos dentro de métodos faz a classe ficar dependente
Dependency injection
Uma classe deve ter uma e apenas uma responsabilidade
Favorecer classes “pequenas” focadas num único aspeto/conceito do problema
Todos os métodos da interface pública da classe devem fazer um conjunto coerente
Permite melhor divisão de tarefas e maior facilidade de manutenção
Uma classe deve ser aberta (open) para extensão mas fechada (close) para modificação
Novos requisitos e comportamentos devem ser obtidos através da extensão da classe e não da sua modificação
Ao criar a classe identificar (possíveis) pontos de futura variabilidade e desenhar a classe para poder ser estendida nesses pontos
Template Method
Strategy
Decorator – veremos mais tarde
Visitor – veremos mais tarde
Don’t touch existing code (bug fixes excluded). You should have no reason to change the internals of a class to add new behaviour, instead you should extend the class with the new behaviour.
Problema:
Permitir que o cliente escolha de muitas alternativas, complexas, sendo que não se deseja incluir código para todas.
Solução:
Fazer muitas implementações da mesma interface, e permitir que o cliente seleccione uma e a devolva.
Definir uma família de algoritmos, encapsular cada um deles, e torná-los permutáveis.
Strategy permite que o algoritmo varie independentemente dos clientes que o usam.
Problem:
Allow functionally to be layered around an abstraction, but still dynamically changeable.
Solution:
Combine inheritance and composition. By making an object that both subclasses from anther class and holds an instance of the class, can add new behavior while referring all other behavior to the original class.
Problem
How to dinamically add new operations to existing data structures?
Solution
Separate the algorithm from the data structure it operates on by creating a visitor that traverses the desired object.
the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures. It is one way to follow the open/closed principle.
In essence, the visitor allows one to add new virtual functions to a family of classes without modifying the classes themselves; instead, one creates a visitor class that implements all of the appropriate specializations of the virtual function. The visitor takes the instance reference as input, and implements the goal through double dispatch.
Qualquer método que espere um objeto de um tipo A deve poder trabalhar com qualquer objeto derivado de A
Classes derivadas devem cumprir o mesmo contrato (sem alterações semânticas) da classe base
Muitas interfaces específicas são melhores que uma única genérica
Classes clientes não devem ser forçadas a depender de interfaces que não necessitam (não usam)
Deve depender-se de abstrações e não de concretizações
Ex., List vs. ArrayList
Criar uma camada de abstração que diminuirá o acoplamento entre módulos
Abstrações tendem a modificar com menos frequência que as concretizações
Clients should depend on abstractions, not concretions. I.e., program to an interface not a realization.
DIP
Deve depender-se de abstrações e não de concretizações
Ex., List vs. ArrayList
Criar uma camada de abstração que diminuirá o acoplamento entre módulos
Problema:
Como diminuir o acoplamento entre classes de camadas diferentes
Solução:
Colocar a interface do serviço num package e a implementação noutro
Diminui o coupling entre classes do sistema evitando que classes de uma camada façam referência directa a outra
Ex., componentes de lógica de acesso a dados chamarem métodos de classes de negócio
Program to an interface not an implementation: Decreases coupling/dependencies among classes
Favour composition instead of inheritance: Don’t inherit behaviour you don’t need. Allow for implementation changes
Consider what should be variable in your design: hide what varies and allow for substitution via common interface
Keep different responsibilities apart from each other: Don’t create big, fat classes
Program to an interface and not to an implementation - Purring this more succinctly, you should define the top of any class hierarchy with an abstract class, which implements no methods, but simply defines the methods that class will support. Then, in all of your derived classes you have more freedom to implement these methods as most suits your purposes. Essentially this means considering the object you are dealing with as a black box. Do not consider how it does its tasks, just consider the interface (set of public methods) that it allows you to use.
Favor object composition over inheritance - While many beginning OO programmers use inheritance to solve every problem when an alternative way is needed to accomplish something. This works well for handling one variation. However, if something else starts to vary you get an exponentially increasing number of possible combinations. Using inheritance alone requires a correspondingly large number of classes (one for each combination). As you begin to write more elaborate programs, the merits of object composition become apparent. Your new object can have the interface that is best for what you want to accomplish without having all the methods of the parent classes.
Consider what should be variable in your design - Focus on encapsulating the concept that varies. Allow substitution of variable implementations via a common interface.