SOLID: Bom Design em Orientação a Objetos
-
Upload
mario-rezende -
Category
Technology
-
view
2.965 -
download
3
description
Transcript of SOLID: Bom Design em Orientação a Objetos
Trilha PHP – SOLIDBom Design em Orientação a Objetos
Mario RezendeDesenvolvedor PHP na Kanui.com.br
Integrante do Grupo de Usuários PHPSP.org.br
❖ Bom Design em OO
❖ Os Princípios do SOLID
❖ Onde o SOLID se “encaixa”
❖ Exemplos de Código
❖ Bônus: Robert Martin & Livros
Agenda
Bom Design em OO
Mudança , Dependência , Acoplamento
1. Mudança de Requisitos
2. Gestão de Dependências
Bom Design em OO
12345678910
1234
class AnotherClass{ public function doSomething() { // logic }}
12345678910
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
Bom Design em OO
Mudança , Dependência , Acoplamento
1234
class AnotherClass{ public function doSomething() { // logic }}
1 class ClassA { // depends AnotherClass }
1 class ClassB { // depends AnotherClass }
12345678910
12345678910
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 }}
Bom Design em OO
Mudança , Dependência , Acoplamento
123456789
1234
class AnotherClass{ public function doSomething() { // logic }}
1234567891011
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 }}
Bom Design em OO
Mudança , Dependência , Acoplamento
123456789
1234
class AnotherClass{ public function doSomething() { // logic }}
1234567891011
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 }}
1234
class DerivedClass extends AnotherClass x{ public function doSomething() { // logic }}
Bom Design em OO
Mudança , Dependência , Acoplamento
12345678910
12345678
class MyClassTest extends PHPUnit_Framework_TestCase{ public function testMyMethod() { $class = new MyClass(); $this->assertEquals(1, $class->myMethod()); }}
1234
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
?
Bom Design em OO
Mudança , Dependência , Acoplamento
12345678910111213141516
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)); }}
123456789
class MyClass{ public function myMethod(AnotherClass $class) { $anyThing = $class->doSomething();
// solves some logic and returns the result }}
1234
class AnotherClass{ public function doSomething() { // logic }}
Bom Design em OO
Manifesto para Desenvolvimento
ÁGIL de Software
Mudança , Dependência , Acoplamento , Ágil
Indivíduos e interaçõesSoftware em funcionamento
Colaboração com o cliente
Responder a Mudanças
Os Princípios do SOLID
S ingle Responsibility
Open / Closed
L iskov Substitution
I nterface Segregation
Dependency Inversion
Mudança , Dependência , Acoplamento , Ágil
Princípios Orientação Objetos
AbstraçãoEncapsulamentoHerançaComposiçãoModularidadePolimorfismo
Princípios de Design de Classe
Padrões de Design
Arquitetura em Camadas
Arquitetura Distribuída
SOAESB
SaaS
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
implementação conceitual
Coesão< AcoplamentoOrtogonalidadeDesign p/ ContratoLei de Deméter
MVCDDDFrameworks
Solução GenéricaProblemas RecorrentesPrograme p/ InterfacePrefira Composição
Onde o SOLID se “encaixa”
Princípios Orientação Objetos
AbstraçãoEncapsulamentoHerançaComposiçãoModularidadePolimorfismo
Princípios de Design de Classe
Padrões de Design
Arquitetura em Camadas
Arquitetura Distribuída
SOAESB
SaaS
Coesão< AcoplamentoOrtogonalidadeDesign p/ ContratoLei de Deméter
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
SOLID
implementação conceitual
MVCDDDFrameworks
Solução GenéricaProblemas RecorrentesPrograme p/ InterfacePrefira Composição
Onde o SOLID se “encaixa”
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Single ResponsibilityUma Classe deve ter uma única razão para mudar
(responsabilidade única)
Exemplos de Código S.O.L.I.D
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Single Responsibility1234567891011121314151617181920
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() {}}
1234567891011121314
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Single Responsibility1234567891011121314
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; }}
12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
123456789101112
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Single Responsibility12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234567
class Sign{ public function authenticate(Customer $customer) { // authenticate user in a database }}
1234567
class Grant{ public function hasRole($role, Customer $customer) { // checks user privileges }}
1234567891011121314
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
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 whatsoftware 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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Open / ClosedEntidades (classes, módulos, etc) devem ser
aberta para extensão, mas fechada para modificação
Exemplos de Código S.O.L.I.D
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Open / Closed S.O.L.I.D12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234567
class Sign{ public function authenticate(Customer $customer) { // authenticate user in a database }}
1234567
class Grant{ public function hasRole($role, Customer $customer) { // checks user privileges }}
1234567891011121314
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; }}
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Open / Closed S.O.L.I.D12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234567891011121314
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; }}
1234567
class Sign{ public function authenticate(Customer $customer) { // authenticate user in a database }}
1234567
class SignFacebook extends Sign x{ public function authenticate(Customer $customer) { // connect to third-party server resource }}
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Open / Closed S.O.L.I.D12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234567891011121314
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; }}
1234567
class Sign { public function authenticate(Customer $customer) { // authenticate user in a database }
protected function getRepository(Adapter $db) x { // connect to database }}
1234567
class SignFacebook extends Sign { public function authenticate(Customer $customer) { // connect to third-party server resource }
protected function getAccessToken(Oauth $client) { // retrieve a valid token }}
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Open / Closed S.O.L.I.D12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
12345678910111213
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; }}
1234567
class SignDatabase implements SignService { x public function authenticate(Customer $customer) { // authenticate user against a database }
protected function getRepository(Adapter $db) { // connect to database }}
1234567
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 }}
1234
interface SignService x { public function authenticate(Customer $customer);}
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 abstractionto every part of the application…
Resisting premature abstraction is as important as abstraction itself.(Robert Martin)
Open / Closed S.O.L.I.D
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
S.O.L.I.D12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
12345678910111213
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; }}
1234567
class SignDatabase implements SignService { public function authenticate(Customer $customer) { // authenticate user against a database }
protected function getRepository(Adapter $db) { // connect to database }}
1234
interface SignService{ public function authenticate(Customer $customer);}
1234567
class Grant{ public function hasRole($role, Customer $customer) { // checks user privileges }}
Dependency Inversion
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Dependency Inversion S.O.L.I.D
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
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
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
12345678910
class Customer implements User{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234
class SignDatabase implements SignService { public function authenticate(Customer $customer) { // authenticate user against a database }}
1234
interface SignService{ public function authenticate(Customer $customer);}
1234
interface GrantService{ public function hasRole($role, Customer $customer)}
1 interface User { // Getter & Setters }
Dependency Inversion S.O.L.I.D12345678910111213
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; }}
1234
class BaseGrant implements GrantService { public function hasRole($role, Customer $customer) { // checks user privileges }}
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
12345678910
class Customer implements User{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234
class SignDatabase implements SignService { public function authenticate(User $user) { // authenticate user against a database }}
1234
interface SignService{ public function authenticate(User $user);}
1234
interface GrantService{ public function hasRole($role, User $user);}
1 interface User { // Getter & Setters }
Dependency Inversion S.O.L.I.D12345678910111213
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; }}
1234
class BaseGrant implements GrantService { public function hasRole($role, User $user) { // checks user privileges }}
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234567
class Sign{ public function authenticate(Customer $customer) { // authenticate user in a database }}
1234567
class Grant{ public function hasRole($role, Customer $customer) { // checks user privileges }}
1234567891011121314
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Dependency Inversion S.O.L.I.D
12345678910
class Customer implements User{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234
interface GrantService{ public function hasRole($role, User $user);}
1 interface User { // Getter & Setters }12345678910111213
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; }}
1234
class BaseGrant implements GrantService { public function hasRole($role, User $user) { // checks user privileges }}
1234567
class SignDatabase implements SignService { public function authenticate(User $user) { // authenticate user against a database }
protected function getRepository(Adapter $db) { // connect to database }}
1234
interface SignService { public function authenticate(User $user); protected function getRepository(Adapter $db);}
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Dependency Inversion S.O.L.I.D
12345678910
class Customer implements User{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1 interface User { // Getter & Setters }12345678910111213
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; }}
1234567
class SignDatabase implements SignService { public function authenticate(User $user) { // authenticate user against a database }
protected function getRepository(Adapter $db) { // connect to database }}
1234
interface SignService { public function authenticate(User $user); protected function getRepository(Adapter $db);}
1234567
class SignFacebook implements SignService { public function authenticate(User $user) { // connect to third-party server resource }
protected function getAccessToken(Oauth $client) { // retrieve a valid token }}
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Dependency Inversion S.O.L.I.D
12345678910
class Customer implements User{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1 interface User { // Getter & Setters }12345678910111213
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; }}
1234567
class SignDatabase implements SignService { public function authenticate(User $user) { // authenticate user against a database }
protected function getRepository(Adapter $db) { // connect to database }}
1234
interface SignService{ public function authenticate(User $user);}
1234567
class SignFacebook implements SignService { public function authenticate(User $user) { // connect to third-party server resource }
protected function getAccessToken(Oauth $client) { // retrieve a valid token }}
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Policy
Utility
Mechanism
Dependency Inversion S.O.L.I.D
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Liskov SubstitutionPossibilidade de Substituir a Classe Base pela sua Derivada,
sem alterar o funcionamento correto do Software
Exemplos de Código S.O.L.I.D
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
1234567891011
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'); }}
1234567
class Payment{ private $type; //CreditCard, Billet private $amount; private $createdAt; //2013-10-01 Tue private $payday;}
1234567891011
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
1234567891011
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'); }}
1234567
class Payment{ private $type; //CreditCard, Billet private $amount; private $createdAt; //2013-10-01 Tue private $payday;}
1234567891011
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'); }}
1234567891011
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
1234567
class Payment{ private $type; //CreditCard, Billet private $amount; private $createdAt; //2013-10-01 Tue private $payday;}
123456789101112
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'); }}
123456789101112
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'); }}
1234567891011
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
1234567
class Payment{ private $type; //CreditCard, Billet private $amount; private $createdAt; //2013-10-01 Tue private $payday;}
123456789101112
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'); }}
123456789101112
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'); }}
1234567891011
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
123456
class PaymentCalcBefore extends PaymentCalculator { protected function resolvePayDay($workDays,$pay) { // calculate D+5 and find PREVIOUS work day return new DateTime('2013-10-04'); // Friday }}
123456789101112
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 }}
1234567
class Payment{ private $type; //CreditCard, Billet private $amount; private $createdAt; //2013-10-01 Tue private $payday;}
1234567891011
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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
123456
class BeforeCalculator extends PaymentCalculator{ protected function resolvePayDay($workDays,$pay) { return new DateTime('2013-10-04'); // Friday }}
1234567891011
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);}
1234567891011
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 }}
123456
class AfterCalculator extends PaymentCalculator{ protected function resolvePayDay($workDays,$pay) { return new DateTime('2013-10-07'); // Monday }}
123
class CCardPayment implements Payment{ // attributes and methods }
1 interface Payment { }
123
class BilletPayment implements Payment { // attributes and methods }
Liskov Substitution S.O.L.I.D
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
123456
class CreditCardCalculator extends PaymentCalculator{ protected function resolvePayDay($workDays,$pay) { return new DateTime('2013-10-04'); // Friday }}
1234567891011
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);}
1234567891011
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 }}
123456
class BilletCalculator extends PaymentCalculator{ protected function resolvePayDay($workDays,$pay) { return new DateTime('2013-10-07'); // Monday }}
1 interface Payment { }
123
class CCardPayment implements Payment{ // attributes and methods }
123
class BilletPayment implements Payment { // attributes and methods }
Liskov Substitution S.O.L.I.D
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
Interface SegregationMuitas 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
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
AtmUI+ requestDeposit+ requestWithdrawl+ requestTransfer+ informeInsufficientFunds
Interface Segregation S.O.L.I.D
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
AtmUI+ requestDeposit+ requestWithdrawl+ requestTransfer+ informeInsufficientFunds
Interface Segregation S.O.L.I.D
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
?Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Dúvidas
S ingle responsibility
Open/closed
L iskov substitution
I nterface segregation
Dependency inversion
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Robert Martin
SOLID
Mudança , Dependência , Acoplamento , Ágil , Composição , Interface
Robert Martin
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