Čtvrtkon #53 - Štěpán Zikmund

Post on 12-Apr-2017

112 views 0 download

transcript

SOLID | Štěpán Zikmund

krása

• změny v zadání

• nové funkce, které jsou v rozporu s původní funkcionalitou

• deadliny

Co by mohly být takový překážky..

no, mohly by…

source code

💩

Rigidity

Fragilitiy

Imobility

Coupling? How?

OOP

SOLID

Single Responsibility Principle Open Closed Principle Liskov Substitution Principle Interface Segregation Principle Dependency Inversion Principle

– Uncle Bob

„OOP is about managing dependency by selectively inverted some key dependencies in your architecture to prevent rigidity, fragility, not

reusability“

The Dependency Inversion Principle

Depend on abstractions, not on concretions

m

n

m n

m interface

n

class Authentication { private $userProvider;

public function __construct(UserProvider $userProvider) { $this->userProvider = $userProvider; } }

class Authentication { private $userProvider;

public function __construct(UserProviderInterface $userProvider) { $this->userProvider = $userProvider; } }

The Single Responsibility Principle

A class should have one, and only one, reason to change

Symptomy

• účel třídy nejde pospat bez spojek a, nebo

• třída obsahuje velké množství properties a public method

• třída obsahuje velké množství závislostí na další objekty

Řešení

• kompozice

• event listener

• …

Employee

+ getSalary() + getName() + setSalary() + setName() + getSalaryReport()

Employee

+ getSalary() + getName() + setSalary() + setName()

SalaryReportBuilder

+ getReport(Employee $employee)

The Open Closed Principle

You should be able to extend a classes behaviour, without modifying it

Pro přidání nové featury nechcete editovat stávající

kód, ale vytvořit nový

function doSomething($howToDoIt) { if ($howToDoIt == 'something') { return someBehaviour(); } else if ($howToDoIt == 'somethingOther') { return someOtherBehaviour(); } else { throw new \IllegalArgumentException(); } }

Symptomy

• switch statement

• třída zná více různých service se stejným interfacem nebo s podobným účelem

Employee

+ getSalary() + getName() + setSalary() + setName()

SalaryReportBuilder

+ getXmlReport(Employee $employee) + getJsonReport(Employee $employee)

Employee

+ getSalary() + getName() + setSalary() + setName()

SalaryReportBuilder

+ getXmlReport(Employee $employee) + getJsonReport(Employee $employee)SRP

XmlReportBuilder

+ getXmlReport(..)

SalaryReportBuilder

+ getReport($type)

JsonReportBuilder

+ getJsonReport(..)

function getReport($type, $employee) { switch ($type): case 'xml' return $this->xmlReportBuilder->getReport($employee); case 'json' return $this->jsonReportBuilder->getReport($employee); default: throw new \IllegalArgumentException(); }

function getReport($type, $employee) { switch ($type): case 'xml' return $this->xmlReportBuilder->getReport($employee); case 'json' return $this->jsonReportBuilder->getReport($employee); default: throw new \IllegalArgumentException(); } OCP

XmlReportBuilder

+ getReport(..) + getName()

SalaryReportBuilder

+ addBuilder(ReportInterface) + getReport($type)

ReportBuilderInterface

+ getReport(..) + getName

JsonReportBuilder

+ getReport(..) + getName()

function getReport($type, $employee) { foraech ($this->reportBuilders as $builder) { if ($builder->getName() == $type) { return $builder->getReport($employee); } }

throw new \IllegalArgumentException(); }

The Liskov Substitution Principle

Derived classes must be substitutable for their base classes.

app rectangle

app rectangle

square

class Square { public function setHeight($height) { $this->height = $height; parent::setWidth($height); } public function setWidth($width) { $this->width = $width; parent::setHeight($width); } }

if ($rectangle instanceof Square) { //.. } else { //.. }

app rectangle

square

OOP není modelování skutečného světa, ale

jeho reprezentací

class Rectangle { public function getHeight() {} public function getWidth() {} public function setHeight() {} public function setWidth() {} }

class Square { public function getSize() {} public function setSize() {} }

The Interface Segregation Principle

Make fine grained interfaces that are client specific

m interface

n

Client specific?

m interface

n

Fine grained?

interface FileInterface { public function changeName() public function changeOwner() }

class DropboxFile implements FileInterface { public function changeName() { } public function changeOwner() { // don’t need this method } }

interface FileInterface { public function changeName() }

interface SupportsChangeOfOwnershipInterface { public function changeOwner() }

SRP OCP LSP ISP DIP