solid principles

Post on 18-May-2015

1.420 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Early in year 2000 Robert C. Martin, aka "Uncle Bob", introduced his thoughts in an article about some of five basic principles on object oriented programming to the open world. What he probably did not expect was, that this 5 principles became the standard for object oriented programming. This Talk is about those principles: Single responsibility, Open/close, Liskov substitution, Interface segregation, and Dependency inversion, or shorter S.O.L.I.D. principles. It will give you an introduction about these principles, their meaning, and where they should be recognized and applied. Examples from my daily work will show you the practical aspects of those principles.

TRANSCRIPT

S.O.L.I.DPrinciples

Bastian Federbastian.feder@liip.ch

OSIDays 2011, Bangalore21st November 2011

Me, myself & I

PHP since 2001

Testing and Quality coach @ Liip Inc.

Opensource addict

PHP manual translations

FluentDOM

phpDox

News from Uncle Bob

Essential principles for software development & object oriented design (OOD).

Robert C. Martin summarized those principles, but did not invent them.

Which are these principles?

Single responsibility principle

Open/Close principle

Liskov substitution principle

Interface segregation principle

Dependency inversion principle

Geolocation Tracker

„As a hiker I want to track where I walked and how much I climbed.“

„As a developer I want to be able to store the geo information on different devices.“

„As a developer I want to store the geo information in a unified format.“

Single responsibilityprinciple (SRP)

„A class should have one, and only one, reason to change.“

How to doit wrong

<?phpnamespace lapis\Tracker;use lapis\Tracker\Structs;

class Geolocation extends Tracker{ public function trackPosition(Position $position) { list($langitude, $longitude, $altitude) = $this->extractCoordinatesFromPosition($position); $altitude = $this->convertFeetToMeter($altitude); $this->persistPosition($langitude, $longitude, $altitude, new DateTime()); }

public function persistPosition( $langitude, $longitude, $altitude, \DateTime $time) { try{ $conn = $this->getDatabaseConnection('write'); $conn->execute($this->generateQuery($langitude, $longitude, $altitude, $time)); } catch (Exception $e) { $this->logError($e->getMessage()); } } /** […] */}

How to doit right

<?php

namespace lapis\Tracker;use lapis\Tracker\Structs\Position;

class Geolocation extends Tracker{ public function __construct(Parser $parser, PersistenceManager $pm) { /** […] */ }

public function trackPosition(Position $position, \DateTime $time = null) { try { $coordinates = $this->parser->parsePosition($position); $this->pm->persistPosition($coordinates, $time); } catch (PersistanceManagerException $e) { throw new TrackerException( 'Unable to persist your position.', TrackerException::PersistError, $e ); } }}

Single responsibilityprinciple

Simple to understand, very hard to get right.

Separation of responsibilities / concerns

One responsibility per class

Liskov substitutionprinciple (LSP)

„Derived classes must be substitutable for their base

classes.“

Where dowe start

<?phpnamespace lapis\Converter;

class Distance { const FACTOR = 0.3048; // 1 foot in meters

public function feetToMeters($distance) { $this->verifyDistance($distance); return $distance * self::FACTOR; }

public function metersToFeet($distance) { $this->verifyDistance($distance); return $distance / self::FACTOR; }

protected function verifyDistance($distance) { if ($distance < 0) { throw new \OutOfRangeException( 'Distance may not be lower than zero.', DistanceException::OutOfRange ); } }}

How to doit wrong

<?php

namespace lapis\Converter\Distance;use lapis\Converter;

class NegativeDistance extends Distance{ protected function verifyDistance($distance) { return TRUE; }}

How to doit right

<?phpnamespace lapis\Converter\Distance;use lapis\Converter;

class MaxDistance extends Distance { public function feetToMeters($distance) { $distance = parent::feetToMeters($distance); $this->verifyDistance($distance, 15000); return $distance; }

protected function verifyDistance($distance, $max = 0) { if ($distance < 0) { $message = 'Distance may not be lower than the zero.'; } if ($max > 0 && $distance >= $max) { $message = 'Distance may not be greater than the maximum of ' . $max . '.'; } If (isset($message) { throw new \OutOfRangeException($message, DistanceException::OutOfRange); } }}

Liskov substitutionprinciple

Design by contract

User must not distinguish between super- & subclasses

Derived class must be more strict on output, but may handle the input less strict.

Increases maintainability, robustness & resusability

Dependency inversionprinciple (DIP)

„Depend on abstractions, not on concretions.“

How to doit wrong

<?phpnamespace lapis\Tracker;use lapis\Tracker\Structs\Position;

class PersistenceManager { public function __construct(Tracker $tracker) { /** […] */ }

public function trackPosition(Position $position) { try { $this->tracker->trackPosition($position); $this->log('Position stored successfully'); } catch (TrackerException $e) { $this->log($e->getMessage()); } }

protected function log($message) { $fh = fopen ('log.txt' , 'a'); fwrite($fh, $message); fclose($fh); } /** […] */}

How to doit right

<?php

namespace lapis\Tracker;use lapis\Logger, lapis\Tracker\Services;

class PersistenceManager{ public function __construct(PersistService $ps, Logger $logger) { /** […] */ }

public function persistPosition($coordinates, \DateTime $time = null) { try { $this->ps->setCoordinates($coordinates); $this->ps->setTimeStamp($time); $this->ps->persist(); $this->logger->log('Position stored successfully');

} catch (PersistServiceException $e) { $this->logger->exception($e); } }}

Dependency inversionprinciple

Fundamental principle for OOD

Encapsulate low level modules in abstractions

Depend on abstractions / interfaces rather than implementations

Interface segregationprinciple (ISP)

„Make fine grained interfaces that are client specific.“

Where dowe start

<?php

namespace lapis\Tracker;use lapis\Logger, lapis\Tracker\Services;

class PersistenceManager{ public function __construct(PersistService $ps, Logger $logger) { /** […] */ }

public function persistPosition($coordinates, \DateTime $time = null) { try { $this->ps->setCoordinates($coordinates); $this->ps->setTimeStamp($time); $this->ps->persist(); $this->logger->log('Position stored successfully');

} catch (PersistServiceException $e) { $this->logger->exception($e); } }}

How to doit right

<?php

namespace lapis\Tracker;use lapis\Logger, lapis\Tracker\Services;

class PersistenceManager implements PersistenceManagerPosition{ public function __construct(PersistService $ps, Logger $logger) { /** […] */ }

public function persistPosition($coordinates, \DateTime $time = null) { /** […] */ }

public function persistHeight($height, \DateTime $time = null) { /** […] */ }

public function persistLocation($height, \DateTime $time = null) { /** […] */ }}

interface PersistenceManagerPosition{ public function persistPosition($coordinates, \DateTime $time = null);}

<?php

namespace lapis\Tracker;use lapis\Tracker\Structs\Position;

class Geolocation extends Tracker{ public function __construct(Parser $parser, PersistenceManagerPosition $pm) { /** […] */ }

public function trackPosition(Position $position, \DateTime $time = null) { try{ $coordinates = $this->parser->parsePosition($position); $this->pm->persistPosition($coordinates, $time); } catch (PersistanceManagerException $e) { throw new TrackerException( 'Unable to persist your position.', TrackerException::PersistError, $e ); } }}

Interface segregationprinciple

Avoid „fat“ interfaces, stick to what's really needed

Ask yourself „What do I want to archieve?“

Be strict!

Open/Close principle (OCP)

„You should be able to extend a classes behavior, without modifying

it.“

Open/Close principle (OCP)

„It is the heard of object oriented design“

Combines the other 4 principles

Where we started

Where we got

Questions@lapistano

bastian.feder@liip.ch

PHP5.3 Powerworkshop

New features of PHP5.3

Best Pratices using OOP

PHPUnit

PHPDocumentor

License

This set of slides and the source code included in the download package is licensed under the

Creative Commons Attribution-Noncommercial-Share Alike 2.0 Generic License

http://creativecommons.org/licenses/by-nc-sa/2.0/deed.en

top related