1 Chapter 22 Object-Oriented Design. 2 Object-Oriented Design.
Solid: Good Object Oriented Design
-
Upload
mario-rezende -
Category
Technology
-
view
1.134 -
download
1
description
Transcript of Solid: Good Object Oriented Design
Mario Rezende
http://about.me/mariorez
SOLIDGood Object Oriented Design
Agenda
❖ Good OO Design
❖ The principles of SOLID
❖ Where SOLID “fits”
❖ The Principles by examples
❖ Bonus: Robert Martin & Books
Good OO Design
Change , Dependency , Coupling
1. Changing Requirements
2. Dependency Management
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 }}
Good OO Design
Change , Dependency , Coupling
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 }}
Good OO Design
Change , Dependency , Coupling
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 }}
Good OO Design
Change , Dependency , Coupling
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 }}
Good OO Design
Change , Dependency , Coupling
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 }}
what will be the result of this test
?
Good OO Design
Change , Dependency , Coupling
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($stub); $this->assertEquals(1, $class->myMethod()); }}
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 }}
Good OO Design
Change , Dependency , Coupling
Manifesto for AGILE Software Development
Individuals and interactionsWorking software
Customer collaboration
Responding to change
Good OO Design
Change , Dependency , Coupling, Agile
S ingle Responsibility
Open / Closed
L iskov Substitution
I nterface Segregation
Dependency Inversion
The principles of SOLID
Change , Dependency , Coupling, Agile
Object Oriented Principles
AbstractionEncapsulationInheritanceCompositionModularityPolymorphism
Principles of Class Design
Design Patterns
Layered Architecture
CohesionLow CouplingOrthogonalityDesign by ContractLaw of Demeter
MVCDDD
Frameworks
General SolutionRecurring problemsProgram to InterfaceFavor Composition
GranularityStabilityMetrics forstability and abstraction
implementation conceptual
Principles of Package and Component Design
Where SOLID “fits”
Change , Dependency , Coupling, Agile , Composition , Interface
Object Oriented Principles
AbstractionEncapsulationInheritanceCompositionModularityPolymorphism
Principles of Class Design
Design Patterns
Layered Architecture
CohesionLow CouplingOrthogonalityDesign by ContractLaw of Demeter
MVCDDD
Frameworks
General SolutionRecurring problemsProgram to InterfaceFavor Composition
GranularityStabilityMetrics forstability and abstraction
implementation conceptual
Principles of Package and Component Design
Where SOLID “fits”
Change , Dependency , Coupling, Agile , Composition , Interface
SOLID
The Principles by examples S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Single ResponsibilityA class should have only a single responsibility
(only one reason to change)
Single Responsibility1234567891011121314151617181920
class Customer{ public function authenticate() { // authenticate user against a database }
public function authorize() { // 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->authorize()) { return true; } return false; }}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
1234567891011121314
class AccessControlManager{ public function __construct(Customer $customer, Login $login) { //save references }
public function login() { if ($this->login->authenticate($this->customer) && $this->login->authorize($this->customer)) { return true; } return false; }}
Single Responsibility12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
123456789101112
class Login{ public function authenticate(Customer $customer) { // authenticate user against a database }
public function authorize(Customer $customer) { // checks user privileges }}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Single Responsibility12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234567
class SignIn{ public function authenticate(Customer $customer) { // authenticate user against a database }}
1234567
class Permission{ public function authorize(Customer $customer) { // checks user privileges }}
12345678910111213
class AccessControlManager { public function __construct(Customer $customer, SignIn $sign, Permission $perm) { //save references }
public function login() { if ($this->sign->authenticate($this->customer) && $this->perm->authorize($this->customer)) { return true; } return false; }}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Single Responsibility S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Conclusion❖ SRP is the simplest, and the most difficult to get right
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)
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
The Principles by examples
Open / ClosedSoftware entities (classes, modules, functions, etc.)
should be open for extension, but closed for modification
12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
Open / Closed
1234567
class SignIn{ public function authenticate(Customer $customer) { // authenticate user against a database }}
1234567
class Permission{ public function authorize(Customer $customer) { // checks user privileges }}
12345678910111213
class AccessControlManager { public function __construct(Customer $customer, SignIn $sign, Permission $perm) { //save references }
public function login() { if ($this->sign->authenticate($this->customer) && $this->perm->authorize($this->customer)) { return true; } return false; }}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
Open / Closed
1234567
class SignIn{ public function authenticate(Customer $customer) { // authenticate user against a database }}
1234567
class SignFacebook extends SignIn x{ public function authenticate(Customer $customer) { // connect to third-party server resource }}
12345678910111213
class AccessControlManager { public function __construct(Customer $customer, SignIn $sign, Permission $perm) { //save references }
public function login() { if ($this->sign->authenticate($this->customer) && $this->perm->authorize($this->customer)) { return true; } return false; }}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Open / Closed12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234567
class SignIn { public function authenticate(Customer $customer) { // authenticate user against a database }
protected function getRepository(Adapter $db) x { // connect to database }}
1234567
class SignFacebook extends SignIn { public function authenticate(Customer $customer) { // connect to third-party server resource }
protected function getAccessToken(Oauth $client) { // retrieve a valid token }}
12345678910111213
class AccessControlManager { public function __construct(Customer $customer, SignIn $sign, Permission $perm) { //save references }
public function login() { if ($this->sign->authenticate($this->customer) && $this->perm->authorize($this->customer)) { return true; } return false; }}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Open / Closed12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
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 { public function authenticate(Customer $customer);}
12345678910111213
class AccessControlManager { public function __construct(Customer $customer, SignService $sign, Permission $perm) { //save references }
public function login() { if ($this->sign->authenticate($this->customer) && $this->perm->authorize($this->customer)) { return true; } return false; }}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Open / Closed S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Conclusion❖ OCP is at the heart of object-oriented design
❖ Flexibility, Reusability and Maintainability
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)
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
The Principles by examples
Dependency Inversion A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend upon details. Details should depend upon abstractions.
Dependency Inversion12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
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 Permission{ public function authorize(Customer $customer) { // checks user privileges }}
12345678910111213
class AccessControlManager { public function __construct(Customer $customer, SignService $sign, Permission $perm) { //save references }
public function login() { if ($this->sign->authenticate($this->customer) && $this->perm->authorize($this->customer)) { return true; } return false; }}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Dependency Inversion S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Dependency Inversion
A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Dependency InversionPolicy
Mechanism
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
Dependency InversionPolicy
Mechanism
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
Dependency Inversion
12345678910
class Customer implements UserIdentity{ 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
class Permission implements GrantService { public function authorize(Customer $customer) { // checks user privileges }}
12345678910111213
class AccessControlManager { public function __construct(UserIdentity $user, SignService $sign, GrantService $grant) { //save references }
public function login() { if ($this->sign->authenticate($this->user) && $this->grant->authorize($this->user)) { return true; } return false; }}
1234
interface SignService{ public function authenticate(Customer $customer);}
1234
interface GrantService{ public function authorize(Customer $customer);}
1 interface UserIdentity { }
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Dependency Inversion
12345678910
class Customer implements UserIdentity{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234
class SignDatabase implements SignService { public function authenticate(UserIdentity $user) { // authenticate user against a database }}
1234
class Permission implements GrantService { public function authorize(UserIdentity $user) { // checks user privileges }}
12345678910111213
class AccessControlManager { public function __construct(UserIdentity $user, SignService $sign, GrantService $grant) { //save references }
public function login() { if ($this->sign->authenticate($this->user) && $this->grant->authorize($this->user)) { return true; } return false; }}
1234
interface SignService{ public function authenticate(UserIdentity $user);}
1234
interface GrantService{ public function authorize(UserIdentity $user);}
1 interface UserIdentity { }
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Dependency Inversion
B. Abstractions should not depend upon details. Details should depend upon abstractions.
S.O.L.I.DPolicy
Mechanism
Change , Dependency , Coupling, Agile , Composition , Interface
12345678910111213
class AccessControlManager { public function __construct(Customer $customer, SignIn $sign, Permission $perm) { //save references }
public function login() { if ($this->sign->authenticate($this->customer) && $this->perm->authorize($this->customer)) { return true; } return false; }}
Dependency Inversion12345678910
class Customer{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1234567
class SignIn { public function authenticate(Customer $customer) { // authenticate user against a database }
protected function getRepository(Adapter $db) { // connect to database }}
1234567
class Permission{ public function authorize(Customer $customer) { // checks user privileges }}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Dependency Inversion
1234567
class SignDatabase implements SignService { public function authenticate(UserIdentity $user) { // authenticate user against a database }
protected function getRepository(Adapter $db) { // connect to database }}
12345678910
class Customer implements UserIdentity{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1 interface UserIdentity { }
1234
interface SignService { public function authenticate(UserIdentity $user); protected function getRepository(Adapter $db);}
12345678910111213
class AccessControlManager { public function __construct(UserIdentity $user, SignService $sign, GrantService $grant) { //save references }
public function login() { if ($this->sign->authenticate($this->user) && $this->grant->authorize($this->user)) { return true; } return false; }}
1234
class Permission implements GrantService { public function authorize(UserIdentity $user) { // checks user privileges }}
1234
interface GrantService{ public function authorize(UserIdentity $user);}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Dependency Inversion
12345678910
class Customer implements UserIdentity{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1 interface UserIdentity { }
1234567
class SignFacebook implements SignService { public function authenticate(UserIdentity $user) { // connect to third-party server resource }
protected function getAccessToken(Oauth $client) { // retrieve a valid token }}
12345678910111213
class AccessControlManager { public function __construct(UserIdentity $user, SignService $sign, GrantService $grant) { //save references }
public function login() { if ($this->sign->authenticate($this->user) && $this->grant->authorize($this->user)) { return true; } return false; }}
1234567
class SignDatabase implements SignService { public function authenticate(UserIdentity $user) { // authenticate user against a database }
protected function getRepository(Adapter $db) x { // connect to database }}
1234
interface SignService { public function authenticate(UserIdentity $user); protected function getRepository(Adapter $db); x}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Dependency Inversion
12345678910
class Customer implements UserIdentity{ public function setEmail($email) {}
public function getEmail() {}
public function setPassword($password) {}
public function getPassword() {}}
1 interface UserIdentity { }
1234567
class SignFacebook implements SignService { public function authenticate(UserIdentity $user) { // connect to third-party server resource }
protected function getAccessToken(Oauth $client) { // retrieve a valid token }}
12345678910111213
class AccessControlManager { public function __construct(UserIdentity $user, SignService $sign, GrantService $grant) { //save references }
public function login() { if ($this->sign->authenticate($this->user) && $this->grant->authorize($this->user)) { return true; } return false; }}
1234567
class SignDatabase implements SignService { public function authenticate(UserIdentity $user) { // authenticate user against a database }
protected function getRepository(Adapter $db) { // connect to database }}
1234
interface SignService{ public function authenticate(UserIdentity $user);}
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Dependency Inversion S.O.L.I.DPolicy
Mechanism
Change , Dependency , Coupling, Agile , Composition , Interface
B. Abstractions should not depend upon details. Details should depend upon abstractions.
Dependency InversionPolicy
Utility
Mechanism
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Dependency Inversion S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Conclusion❖ Rules and details should depend on abstractions,
which are defined in terms of use
❖ When abstractions and details are isolated,it's easier to maintain the code
... inversion of dependencies is the hallmark of good object-oriented design.(Robert Martin)
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
The Principles by examples
Liskov SubstitutionObjects in a program should be replaceable
with instances of their subtypes without alteringthe correctness of that program
Liskov Substitution
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'); }}
S.O.L.I.D1234567
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 }}
Change , Dependency , Coupling, Agile , Composition , Interface
Liskov Substitution
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'); }}
S.O.L.I.D1234567
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 }}
Change , Dependency , Coupling, Agile , Composition , Interface
Liskov Substitution S.O.L.I.D1234567
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 }}
Change , Dependency , Coupling, Agile , Composition , Interface
Liskov Substitution S.O.L.I.D1234567
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 }}
Change , Dependency , Coupling, Agile , Composition , Interface
Liskov Substitution
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 }}
S.O.L.I.D1234567
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 }}
Change , Dependency , Coupling, Agile , Composition , Interface
Liskov Substitution
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 }}
S.O.L.I.D
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 }
Change , Dependency , Coupling, Agile , Composition , Interface
Liskov Substitution
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 }}
S.O.L.I.D
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 }
Change , Dependency , Coupling, Agile , Composition , Interface
Liskov Substitution S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Conclusion❖ LSP is one of the prime enablers of OCP
❖ Design by Contract (require no more, promise no less)
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)
S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
The Principles by examples
Interface SegregationMany client-specific interfaces are better than
one general-purpose interface
Interface Segregation S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
AtmUI+ requestDeposit+ requestWithdrawl+ requestTransfer+ informeInsufficientFunds
Interface Segregation S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
AtmUI+ requestDeposit+ requestWithdrawl+ requestTransfer+ informeInsufficientFunds
Interface Segregation S.O.L.I.D
Change , Dependency , Coupling, Agile , Composition , Interface
Conclusion❖ Avoids the use of "Fat Classes"
❖ Breaks the dependence of the clients on methods that they don't invoke
❖ Allows the clients to be independent of one another
?Change , Dependency , Coupling, Agile , Composition , Interface
Questions
Robert Martin
S ingle responsibility
Open/closed
L iskov substitution
I nterface segregation
Dependency inversion
Change , Dependency , Coupling, Agile , Composition , Interface
Robert Martin
SOLID
Change , Dependency , Coupling, Agile , Composition , Interface
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 (Martin Fowler - 2002)Apps para Android
Change , Dependency , Coupling, Agile , Composition , Interface
Recommended Books