SOLID: Bom Design em Orientação a Objetos

  • 2,605 views
Uploaded on

"SOLID" é um acrônimo para um conjunto de princípios a serem utilizados com Orientação a Objetos, e que auxiliam o Desenvolvedor no bom Design de Software tendo em vista melhor reutilização de Classes …

"SOLID" é um acrônimo para um conjunto de princípios a serem utilizados com Orientação a Objetos, e que auxiliam o Desenvolvedor no bom Design de Software tendo em vista melhor reutilização de Classes e Módulos, aplicação de testes unitários e manutenção do Software.

More in: Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
2,605
On Slideshare
0
From Embeds
0
Number of Embeds
4

Actions

Shares
Downloads
74
Comments
2
Likes
43

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Trilha PHP – SOLID Bom Design em Orientação a Objetos Mario Rezende Desenvolvedor PHP na Kanui.com.br Integrante do Grupo de Usuários PHPSP.org.br
  • 2. ❖ Bom Design em OO ❖ Os Princípios do SOLID ❖ Onde o SOLID se “encaixa” ❖ Exemplos de Código ❖ Bônus: Robert Martin & Livros Agenda
  • 3. Bom Design em OO Mudança , Dependência , Acoplamento 1. Mudança de Requisitos 2. Gestão de Dependências
  • 4. Bom Design em OO 1 2 3 4 5 6 7 8 9 10 1 2 3 4 class AnotherClass { public function doSomething() { // logic } } 1 2 3 4 5 6 7 8 9 10 class Controller { public function action() { $myClass = new MyClass(); $result = $myClass->myMethod(); $this->render($result); } } class MyClass { public function myMethod() { $otherClass = new AnotherClass(); x $anyThing = $otherClass->doSomething(); // solves some logic and returns the result } } Mudança , Dependência , Acoplamento
  • 5. Bom Design em OO Mudança , Dependência , Acoplamento 1 2 3 4 class AnotherClass { public function doSomething() { // logic } } 1 class ClassA { // depends AnotherClass } 1 class ClassB { // depends AnotherClass } 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 class Controller { public function action() { $myClass = new MyClass(); $result = $myClass->myMethod(); $this->render($result); } } class MyClass { public function myMethod() { $otherClass = new AnotherClass(); x $anyThing = $otherClass->doSomething(); // solves some logic and returns the result } }
  • 6. Bom Design em OO Mudança , Dependência , Acoplamento 1 2 3 4 5 6 7 8 9 1 2 3 4 class AnotherClass { public function doSomething() { // logic } } 1 2 3 4 5 6 7 8 9 10 11 1 class ClassA { // depends AnotherClass } 1 class ClassB { // depends AnotherClass } class Controller { public function action() { $myClass = new MyClass(); $otherClass = new AnotherClass();xxx xxxxxx $result = $myClass->myMethod($otherClass); $this->render($result); } } class MyClass { public function myMethod(AnotherClass $class) { $anyThing = $class->doSomething(); // solves some logic and returns the result } }
  • 7. Bom Design em OO Mudança , Dependência , Acoplamento 1 2 3 4 5 6 7 8 9 1 2 3 4 class AnotherClass { public function doSomething() { // logic } } 1 2 3 4 5 6 7 8 9 10 11 1 class ClassA { // depends AnotherClass } 1 class ClassB { // depends AnotherClass } class Controller { public function action() { $myClass = new MyClass(); $otherClass = new DerivedClass();xxxxxx xxx $result = $myClass->myMethod($otherClass); $this->render($result); } } class MyClass { public function myMethod(AnotherClass $class) { $anyThing = $class->doSomething(); // solves some logic and returns the result } } 1 2 3 4 class DerivedClass extends AnotherClass x { public function doSomething() { // logic } }
  • 8. Bom Design em OO Mudança , Dependência , Acoplamento 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 class MyClassTest extends PHPUnit_Framework_TestCase { public function testMyMethod() { $class = new MyClass(); $this->assertEquals(1, $class->myMethod()); } } 1 2 3 4 class MyClass { public function myMethod() { $otherClass = new AnotherClass(); x $anyThing = $otherClass->doSomething(); // solves some logic and returns the result } } class AnotherClass { public function doSomething() { // logic } } Este teste irá passar ?
  • 9. Bom Design em OO Mudança , Dependência , Acoplamento 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class MyClassTest extends PHPUnit_Framework_TestCase { public function testMyMethod() { // Create a stub for the AnotherClass class. $stub = $this->getMock('AnotherClass'); x // Configure the stub. $stub->expects($this->any()) ->method('doSomething') ->will($this->returnValue('mon')); x $class = new MyClass(); $this->assertEquals(1, $class->myMethod($stub)); } } 1 2 3 4 5 6 7 8 9 class MyClass { public function myMethod(AnotherClass $class) { $anyThing = $class->doSomething(); // solves some logic and returns the result } } 1 2 3 4 class AnotherClass { public function doSomething() { // logic } }
  • 10. Bom Design em OO Manifesto para Desenvolvimento ÁGIL de Software Mudança , Dependência , Acoplamento , Ágil Indivíduos e interações Software em funcionamento Colaboração com o cliente Responder a Mudanças
  • 11. Os Princípios do SOLID Single Responsibility Open / Closed Liskov Substitution I nterface Segregation Dependency Inversion Mudança , Dependência , Acoplamento , Ágil
  • 12. Princípios Orientação Objetos Abstração Encapsulamento Herança Composição Modularidade Polimorfismo Princípios de Design de Classe Padrões de Design Arquitetura em Camadas Arquitetura Distribuída SOA ESB SaaS Mudança , Dependência , Acoplamento , Ágil , Composição , Interface implementação conceitual Coesão < Acoplamento Ortogonalidade Design p/ Contrato Lei de Deméter MVC DDD Frameworks Solução Genérica Problemas Recorrentes Programe p/ Interface Prefira Composição Onde o SOLID se “encaixa”
  • 13. Princípios Orientação Objetos Abstração Encapsulamento Herança Composição Modularidade Polimorfismo Princípios de Design de Classe Padrões de Design Arquitetura em Camadas Arquitetura Distribuída SOA ESB SaaS Coesão < Acoplamento Ortogonalidade Design p/ Contrato Lei de Deméter Mudança , Dependência , Acoplamento , Ágil , Composição , Interface SOLID implementação conceitual MVC DDD Frameworks Solução Genérica Problemas Recorrentes Programe p/ Interface Prefira Composição Onde o SOLID se “encaixa”
  • 14. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Single Responsibility Uma Classe deve ter uma única razão para mudar (responsabilidade única) Exemplos de Código S.O.L.I.D
  • 15. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Single Responsibility 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Customer { public function authenticate() { // authenticate user in a database } public function hasRole($role) { // checks user privileges } public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class AccessControlManager { public function __construct(Customer $customer) { //save reference } public function login() { if ($this->customer->authenticate() && $this->customer->hasRole('user')) { return true; } return false; } } S.O.L.I.D
  • 16. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Single Responsibility 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class AccessControlManager { public function __construct(Customer $customer, Security $secur) { //save references } public function login() { if ($this->secur->authenticate($this->customer) && $this->secur->hasRole('user', $this->customer)) { return true; } return false; } } 1 2 3 4 5 6 7 8 9 10 class Customer { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 5 6 7 8 9 10 11 12 class Security { public function authenticate(Customer $customer) { // authenticate user in a database } public function hasRole($role, Customer $customer) { // checks user privileges } } S.O.L.I.D
  • 17. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Single Responsibility 1 2 3 4 5 6 7 8 9 10 class Customer { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 5 6 7 class Sign { public function authenticate(Customer $customer) { // authenticate user in a database } } 1 2 3 4 5 6 7 class Grant { public function hasRole($role, Customer $customer) { // checks user privileges } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class AccessControlManager { public function __construct(Customer $customer, Sign $sign, Grant $grant) { //save references } public function login() { if ($this->sign->authenticate($this->customer) && $this->grant->hasRole('user', $this->customer)) { return true; } return false; } } S.O.L.I.D
  • 18. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Conclusão ❖ SRP é o mais simples, e o mais difícil de fazer certo Finding and separating those responsibilities is much of what software design is really about. Indeed, the rest of the principles we discuss come back to this issue in one way or another. (Robert Martin) Single Responsibility S.O.L.I.D
  • 19. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Open / Closed Entidades (classes, módulos, etc) devem ser aberta para extensão, mas fechada para modificação Exemplos de Código S.O.L.I.D
  • 20. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Open / Closed S.O.L.I.D 1 2 3 4 5 6 7 8 9 10 class Customer { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 5 6 7 class Sign { public function authenticate(Customer $customer) { // authenticate user in a database } } 1 2 3 4 5 6 7 class Grant { public function hasRole($role, Customer $customer) { // checks user privileges } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class AccessControlManager { public function __construct(Customer $customer, Sign $sign, Grant $grant) { //save references } public function login() { if ($this->sign->authenticate($this->customer) && $this->grant->hasRole('user', $this->customer)) { return true; } return false; } }
  • 21. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Open / Closed S.O.L.I.D 1 2 3 4 5 6 7 8 9 10 class Customer { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class AccessControlManager { public function __construct(Customer $customer, Sign $sign, Grant $grant) { //save references } public function login() { if ($this->sign->authenticate($this->customer) && $this->grant->hasRole('user', $this->customer)) { return true; } return false; } } 1 2 3 4 5 6 7 class Sign { public function authenticate(Customer $customer) { // authenticate user in a database } } 1 2 3 4 5 6 7 class SignFacebook extends Sign x { public function authenticate(Customer $customer) { // connect to third-party server resource } }
  • 22. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Open / Closed S.O.L.I.D 1 2 3 4 5 6 7 8 9 10 class Customer { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class AccessControlManager { public function __construct(Customer $customer, Sign $sign, Grant $grant) { //save references } public function login() { if ($this->sign->authenticate($this->customer) && $this->grant->hasRole('user', $this->customer)) { return true; } return false; } } 1 2 3 4 5 6 7 class Sign { public function authenticate(Customer $customer) { // authenticate user in a database } protected function getRepository(Adapter $db) x { // connect to database } } 1 2 3 4 5 6 7 class SignFacebook extends Sign { public function authenticate(Customer $customer) { // connect to third-party server resource } protected function getAccessToken(Oauth $client) { // retrieve a valid token } }
  • 23. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Open / Closed S.O.L.I.D 1 2 3 4 5 6 7 8 9 10 class Customer { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 5 6 7 8 9 10 11 12 13 class AccessControlManager { public function __construct(Customer $customer, SignService $sign, Grant $grant) { // references } public function login() { if ($this->sign->authenticate($this->customer) && $this->grant->hasRole('user', $this->customer)) { return true; } return false; } } 1 2 3 4 5 6 7 class SignDatabase implements SignService { x public function authenticate(Customer $customer) { // authenticate user against a database } protected function getRepository(Adapter $db) { // connect to database } } 1 2 3 4 5 6 7 class SignFacebook implements SignService { x public function authenticate(Customer $customer) { // connect to third-party server resource } protected function getAccessToken(Oauth $client) { // retrieve a valid token } } 1 2 3 4 interface SignService x { public function authenticate(Customer $customer); }
  • 24. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Conclusão ❖ OCP está no coração do Design Orientado a Objetos ❖ Flexibilidade, Reutilização e Manutenibilidade Nor is it a good idea to apply rampant abstraction to every part of the application… Resisting premature abstraction is as important as abstraction itself. (Robert Martin) Open / Closed S.O.L.I.D
  • 25. Dependency Inversion A. Módulos de Alto nível não devem depender de módulos de Baixo nível, ambos devem depender de Abstrações B. Abstrações não devem depender de detalhes, Detalhes devem depender de Abstrações Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Exemplos de Código S.O.L.I.D
  • 26. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface S.O.L.I.D 1 2 3 4 5 6 7 8 9 10 class Customer { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 5 6 7 8 9 10 11 12 13 class AccessControlManager { public function __construct(Customer $customer, SignService $sign, Grant $grant) { // references } public function login() { if ($this->sign->authenticate($this->customer) && $this->grant->hasRole('user', $this->customer)) { return true; } return false; } } 1 2 3 4 5 6 7 class SignDatabase implements SignService { public function authenticate(Customer $customer) { // authenticate user against a database } protected function getRepository(Adapter $db) { // connect to database } } 1 2 3 4 interface SignService { public function authenticate(Customer $customer); } 1 2 3 4 5 6 7 class Grant { public function hasRole($role, Customer $customer) { // checks user privileges } } Dependency Inversion
  • 27. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Dependency Inversion S.O.L.I.D
  • 28. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface A. Módulos de Alto nível não devem depender de módulos de Baixo nível, ambos devem depender de Abstrações Dependency Inversion S.O.L.I.D
  • 29. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Policy Mechanism A. Módulos de Alto nível não devem depender de módulos de Baixo nível, ambos devem depender de Abstrações Dependency Inversion S.O.L.I.D
  • 30. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Policy Mechanism A. Módulos de Alto nível não devem depender de módulos de Baixo nível, ambos devem depender de Abstrações Dependency Inversion S.O.L.I.D
  • 31. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface 1 2 3 4 5 6 7 8 9 10 class Customer implements User { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 class SignDatabase implements SignService { public function authenticate(Customer $customer) { // authenticate user against a database } } 1 2 3 4 interface SignService { public function authenticate(Customer $customer); } 1 2 3 4 interface GrantService { public function hasRole($role, Customer $customer) } 1 interface User { // Getter & Setters } Dependency Inversion S.O.L.I.D 1 2 3 4 5 6 7 8 9 10 11 12 13 class AccessControlManager { public function __construct(User $user, SignService $sign, GrantService $grant) { // refs } public function login() { if ($this->sign->authenticate($this->user) && $this->grant->hasRole('user', $this->user)) { return true; } return false; } } 1 2 3 4 class BaseGrant implements GrantService { public function hasRole($role, Customer $customer) { // checks user privileges } }
  • 32. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface 1 2 3 4 5 6 7 8 9 10 class Customer implements User { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 class SignDatabase implements SignService { public function authenticate(User $user) { // authenticate user against a database } } 1 2 3 4 interface SignService { public function authenticate(User $user); } 1 2 3 4 interface GrantService { public function hasRole($role, User $user); } 1 interface User { // Getter & Setters } Dependency Inversion S.O.L.I.D 1 2 3 4 5 6 7 8 9 10 11 12 13 class AccessControlManager { public function __construct(User $user, SignService $sign, GrantService $grant) { // refs } public function login() { if ($this->sign->authenticate($this->user) && $this->grant->hasRole('user', $this->user)) { return true; } return false; } } 1 2 3 4 class BaseGrant implements GrantService { public function hasRole($role, User $user) { // checks user privileges } }
  • 33. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface B. Abstrações não devem depender de detalhes, Detalhes devem depender de Abstrações Policy Mechanism Dependency Inversion S.O.L.I.D
  • 34. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface 1 2 3 4 5 6 7 8 9 10 class Customer { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 5 6 7 class Sign { public function authenticate(Customer $customer) { // authenticate user in a database } } 1 2 3 4 5 6 7 class Grant { public function hasRole($role, Customer $customer) { // checks user privileges } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class AccessControlManager { public function __construct(Customer $customer, Sign $sign, Grant $grant) { //save references } public function login() { if ($this->sign->authenticate($this->customer) && $this->grant->hasRole('user', $this->customer)) { return true; } return false; } } Dependency Inversion S.O.L.I.D
  • 35. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Dependency Inversion S.O.L.I.D 1 2 3 4 5 6 7 8 9 10 class Customer implements User { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 2 3 4 interface GrantService { public function hasRole($role, User $user); } 1 interface User { // Getter & Setters }1 2 3 4 5 6 7 8 9 10 11 12 13 class AccessControlManager { public function __construct(User $user, SignService $sign, GrantService $grant) { // refs } public function login() { if ($this->sign->authenticate($this->user) && $this->grant->hasRole('user', $this->user)) { return true; } return false; } } 1 2 3 4 class BaseGrant implements GrantService { public function hasRole($role, User $user) { // checks user privileges } } 1 2 3 4 5 6 7 class SignDatabase implements SignService { public function authenticate(User $user) { // authenticate user against a database } protected function getRepository(Adapter $db) { // connect to database } } 1 2 3 4 interface SignService { public function authenticate(User $user); protected function getRepository(Adapter $db); }
  • 36. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Dependency Inversion S.O.L.I.D 1 2 3 4 5 6 7 8 9 10 class Customer implements User { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 interface User { // Getter & Setters }1 2 3 4 5 6 7 8 9 10 11 12 13 class AccessControlManager { public function __construct(User $user, SignService $sign, GrantService $grant) { // refs } public function login() { if ($this->sign->authenticate($this->user) && $this->grant->hasRole('user', $this->user)) { return true; } return false; } } 1 2 3 4 5 6 7 class SignDatabase implements SignService { public function authenticate(User $user) { // authenticate user against a database } protected function getRepository(Adapter $db) { // connect to database } } 1 2 3 4 interface SignService { public function authenticate(User $user); protected function getRepository(Adapter $db); } 1 2 3 4 5 6 7 class SignFacebook implements SignService { public function authenticate(User $user) { // connect to third-party server resource } protected function getAccessToken(Oauth $client) { // retrieve a valid token } }
  • 37. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Dependency Inversion S.O.L.I.D 1 2 3 4 5 6 7 8 9 10 class Customer implements User { public function setEmail($email) {} public function getEmail() {} public function setPassword($password) {} public function getPassword() {} } 1 interface User { // Getter & Setters }1 2 3 4 5 6 7 8 9 10 11 12 13 class AccessControlManager { public function __construct(User $user, SignService $sign, GrantService $grant) { // refs } public function login() { if ($this->sign->authenticate($this->user) && $this->grant->hasRole('user', $this->user)) { return true; } return false; } } 1 2 3 4 5 6 7 class SignDatabase implements SignService { public function authenticate(User $user) { // authenticate user against a database } protected function getRepository(Adapter $db) { // connect to database } } 1 2 3 4 interface SignService { public function authenticate(User $user); } 1 2 3 4 5 6 7 class SignFacebook implements SignService { public function authenticate(User $user) { // connect to third-party server resource } protected function getAccessToken(Oauth $client) { // retrieve a valid token } }
  • 38. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface B. Abstrações não devem depender de detalhes, Detalhes devem depender de Abstrações Policy Mechanism Dependency Inversion S.O.L.I.D
  • 39. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Policy Utility Mechanism Dependency Inversion S.O.L.I.D
  • 40. Conclusão ❖ Regras e detalhes devem depender de abstrações, que são definidas do ponto de vista do uso ❖ Quando as abstrações e detalhes estão isolados, é mais fácil de dar manutenção no código ... inversion of dependencies is the hallmark of good object-oriented design. (Robert Martin) Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Dependency Inversion S.O.L.I.D
  • 41. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Liskov Substitution Possibilidade de Substituir a Classe Base pela sua Derivada, sem alterar o funcionamento correto do Software Exemplos de Código S.O.L.I.D
  • 42. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface 1 2 3 4 5 6 7 8 9 10 11 class PaymentCalculator { public function calculatePayday(Payment $pay) { $calendar = $this->getBrazilianCalendar(); $workDays = $this->getWorkDays($calendar); // calculate 5+ days: 2013-10-06 Sunday // find NEXT work day: 2013-10-07 Monday return new DateTime('2013-10-07'); } } 1 2 3 4 5 6 7 class Payment { private $type; //CreditCard, Billet private $amount; private $createdAt; //2013-10-01 Tue private $payday; } 1 2 3 4 5 6 7 8 9 10 11 class PaymentManager { public function __construct(Payment $payment, PaymentCalculator $calc) { // save references } public function schedulePayment() { $payday = $this->calc->calculatePayday($this->payment); $this->payment->setPayday($payday); // save in database } } Liskov Substitution S.O.L.I.D
  • 43. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface 1 2 3 4 5 6 7 8 9 10 11 class PaymentCalculator { public function calculatePayday(Payment $pay) { $calendar = $this->getBrazilianCalendar(); $workDays = $this->getWorkDays($calendar); // calculate 5+ days: 2013-10-06 Sunday // find NEXT work day: 2013-10-07 Monday return new DateTime('2013-10-07'); } } 1 2 3 4 5 6 7 class Payment { private $type; //CreditCard, Billet private $amount; private $createdAt; //2013-10-01 Tue private $payday; } 1 2 3 4 5 6 7 8 9 10 11 class PaymentCalcBefore extends PaymentCalculator { public function calculatePayday(Payment $pay) { $calendar = $this->getBrazilianCalendar(); $workDays = $this->getWorkDays($calendar); // calculate 5+ days: 2013-10-06 Sunday // find PREV work day: 2013-10-04 Friday return date('2013-10-04'); } } 1 2 3 4 5 6 7 8 9 10 11 class PaymentManager { public function __construct(Payment $payment, PaymentCalculator $calc) { // save references } public function schedulePayment() { $payday = $this->calc->calculatePayday($this->payment); $this->payment->setPayday($payday); // save in database } } Liskov Substitution S.O.L.I.D
  • 44. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface 1 2 3 4 5 6 7 class Payment { private $type; //CreditCard, Billet private $amount; private $createdAt; //2013-10-01 Tue private $payday; } 1 2 3 4 5 6 7 8 9 10 11 12 class PaymentCalcBefore extends PaymentCalculator { /** @return String */ x public function calculatePayday(Payment $pay) { $calendar = $this->getBrazilianCalendar(); $workDays = $this->getWorkDays($calendar); // calculate 5+ days: 2013-10-06 Sunday // find PREV work day: 2013-10-04 Friday return date('2013-10-04'); } } 1 2 3 4 5 6 7 8 9 10 11 12 class PaymentCalculator { /** @return DateTime */ x public function calculatePayday(Payment $pay) { $calendar = $this->getBrazilianCalendar(); $workDays = $this->getWorkDays($calendar); // calculate 5+ days: 2013-10-06 Sunday // find NEXT work day: 2013-10-07 Monday return new DateTime('2013-10-07'); } } 1 2 3 4 5 6 7 8 9 10 11 class PaymentManager { public function __construct(Payment $payment, PaymentCalculator $calc) { // save references } public function schedulePayment() { $payday = $this->calc->calculatePayday($this->payment); $this->payment->setPayday($payday); // save in database } } Liskov Substitution S.O.L.I.D
  • 45. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface 1 2 3 4 5 6 7 class Payment { private $type; //CreditCard, Billet private $amount; private $createdAt; //2013-10-01 Tue private $payday; } 1 2 3 4 5 6 7 8 9 10 11 12 class PaymentCalcBefore extends PaymentCalculator { /** @return DateTime */ x public function calculatePayday(Payment $pay) { $calendar = $this->getBrazilianCalendar(); $workDays = $this->getWorkDays($calendar); // calculate 5+ days: 2013-10-06 Sunday // find PREV work day: 2013-10-04 Friday return new DateTime('2013-10-04'); } } 1 2 3 4 5 6 7 8 9 10 11 12 class PaymentCalculator { /** @return DateTime */ x public function calculatePayday(Payment $pay) { $calendar = $this->getBrazilianCalendar(); $workDays = $this->getWorkDays($calendar); // calculate 5+ days: 2013-10-06 Sunday // find NEXT work day: 2013-10-07 Monday return new DateTime('2013-10-07'); } } 1 2 3 4 5 6 7 8 9 10 11 class PaymentManager { public function __construct(Payment $payment, PaymentCalculator $calc) { // save references } public function schedulePayment() { $payday = $this->calc->calculatePayday($this->payment); $this->payment->setPayday($payday); // save in database } } Liskov Substitution S.O.L.I.D
  • 46. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface 1 2 3 4 5 6 class PaymentCalcBefore extends PaymentCalculator { protected function resolvePayDay($workDays,$pay) { // calculate D+5 and find PREVIOUS work day return new DateTime('2013-10-04'); // Friday } } 1 2 3 4 5 6 7 8 9 10 11 12 class PaymentCalculator { public function calculatePayday(Payment $pay) { $calendar = $this->getBrazilianCalendar(); $workDays = $this->getWorkDays($calendar); return $this->resolvePayDay($workDays, $pay); } protected function resolvePayDay($workDays,$pay) { // calculate D+5 and find NEXT work day return new DateTime('2013-10-07'); // Monday } } 1 2 3 4 5 6 7 class Payment { private $type; //CreditCard, Billet private $amount; private $createdAt; //2013-10-01 Tue private $payday; } 1 2 3 4 5 6 7 8 9 10 11 class PaymentManager { public function __construct(Payment $payment, PaymentCalculator $calc) { // save references } public function schedulePayment() { $payday = $this->calc->calculatePayday($this->payment); $this->payment->setPayday($payday); // save in database } } Liskov Substitution S.O.L.I.D
  • 47. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface 1 2 3 4 5 6 class BeforeCalculator extends PaymentCalculator { protected function resolvePayDay($workDays,$pay) { return new DateTime('2013-10-04'); // Friday } } 1 2 3 4 5 6 7 8 9 10 11 abstract class PaymentCalculator { public function calculatePayday(Payment $pay) { $calendar = $this->getBrazilianCalendar(); $workDays = $this->getWorkDays($calendar); return $this->resolvePayDay($workDays,$payment); } abstract protected function resolvePayDay($wd,$p); } 1 2 3 4 5 6 7 8 9 10 11 class PaymentManager { public function __construct(Payment $payment, PaymentCalculator $calc) { // save references } public function schedulePayment() { $payday = $this->calc->calculatePayday($this->payment); $this->payment->setPayday($payday); // save in database } } 1 2 3 4 5 6 class AfterCalculator extends PaymentCalculator { protected function resolvePayDay($workDays,$pay) { return new DateTime('2013-10-07'); // Monday } } 1 2 3 class CCardPayment implements Payment { // attributes and methods } 1 interface Payment { } 1 2 3 class BilletPayment implements Payment { // attributes and methods } Liskov Substitution S.O.L.I.D
  • 48. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface 1 2 3 4 5 6 class CreditCardCalculator extends PaymentCalculator { protected function resolvePayDay($workDays,$pay) { return new DateTime('2013-10-04'); // Friday } } 1 2 3 4 5 6 7 8 9 10 11 abstract class PaymentCalculator { public function calculatePayday(Payment $pay) { $calendar = $this->getBrazilianCalendar(); $workDays = $this->getWorkDays($calendar); return $this->resolvePayDay($workDays,$payment); } abstract protected function resolvePayDay($wd,$p); } 1 2 3 4 5 6 7 8 9 10 11 class PaymentManager { public function __construct(Payment $payment, PaymentCalculator $calc) { // save references } public function schedulePayment() { $payday = $this->calc->calculatePayday($this->payment); $this->payment->setPayday($payday); // save in database } } 1 2 3 4 5 6 class BilletCalculator extends PaymentCalculator { protected function resolvePayDay($workDays,$pay) { return new DateTime('2013-10-07'); // Monday } } 1 interface Payment { } 1 2 3 class CCardPayment implements Payment { // attributes and methods } 1 2 3 class BilletPayment implements Payment { // attributes and methods } Liskov Substitution S.O.L.I.D
  • 49. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Conclusão ❖ LSP é o principal facilitador do OPC ❖ Design by Contract (não peça demais, não prometa menos) The term IS-A is too broad to act as a definition of a subtype. The true definition of a subtype is substitutable ... (Robert Martin) Liskov Substitution S.O.L.I.D
  • 50. Interface Segregation Muitas Interfaces específicas são melhores do que uma Inferface de proposito geral Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Exemplos de Código S.O.L.I.D
  • 51. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface AtmUI + requestDeposit + requestWithdrawl + requestTransfer + informeInsufficientFunds Interface Segregation S.O.L.I.D
  • 52. Mudança , Dependência , Acoplamento , Ágil , Composição , Interface AtmUI + requestDeposit + requestWithdrawl + requestTransfer + informeInsufficientFunds Interface Segregation S.O.L.I.D
  • 53. Conclusão ❖ Evita a utilização de “Fat Classes” ❖ Quebra a dependência de métodos que não são invocados pelos clientes ❖ Permite a independência entre clientes Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Interface Segregation S.O.L.I.D
  • 54. ?Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Dúvidas
  • 55. Single responsibility Open/closed Liskov substitution I nterface segregation Dependency inversion Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Robert Martin
  • 56. S O L I D Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Robert Martin
  • 57. Agile Software Development, Principles, Patterns, and Practices (Robert Martin - 2002) Agile Principles, Patterns, and Practices in C# (Robert Martin - 2006) SOLID e Design Patterns The Pragmatic Programmer (Andrew Hunt and Devid Thomas - 1999) Coesão, Acoplamento, Ortogonalidade, Design por Contrato, Lei de Deméter Clean Code: A Handbook of Agile Software Craftsmanship (Robert C. Martin - 2008) Lei de Deméter, Data Transfer Objects, TDD Domain-Driven Design: Tackling Complexity in the Heart of Software (Erich Evans - 2003) Design Patterns: Elements of Reusable Object-Oriented Software (Gang of Four - 1994) Patterns of Enterprise Applications Architecture (PoeAA: Martin Fowler - 2002) Apps para Android Mudança , Dependência , Acoplamento , Ágil , Composição , Interface Livros Recomendados
  • 58. VALEU !!! Mario Rezende http://about.me/mariorez