Принципы объектно-ориентированного проектирования

31
Принципы объектно-ориентированного проектирования Interlabs 28 марта 2013 1/1

Post on 24-Jan-2015

802 views

Category:

Technology


4 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Принципы объектно-ориентированного проектирования

Принципыобъектно-ориентированного

проектирования

Interlabs

28 марта 2013

1 / 1

Page 2: Принципы объектно-ориентированного проектирования

Лирическое отступление

Алан Кей

• термин и концепция ООП;• язык и интегрированная средаразработки Smalltalk;

• современная система GUI сперекрывающимися окнами;

• концепция планшетного компьютера:Dynabook;

• свободная реализация Smalltalk:Squeak;

• виртуальные 3D миры для совместнойдеятельности Croquet;

2 / 1

Page 3: Принципы объектно-ориентированного проектирования

Объектно-ориентированноепрограммирование

Вообще говоря, бывает сильно разное, в нашем случае:

• функциональность реализуется в виде набора объектов,объединяющих данные и поведение;

• объекты группируются в классы;• классы образуют иерархию;• объекты взаимодействуют между собой, обмениваясьсообщениями по четко определенным протоколам.

3 / 1

Page 4: Принципы объектно-ориентированного проектирования

Инкапсуляция

Детали реализации должны быть скрыты от потребителя:

• поведение объекта описывается набором четкоопределенных операций, формирующих интерфейсвзаимодействия с объектом;

• состояние объекта может быть изменено извне толькочерез внешний интерфейс;

• весь вспомогательный код должен быть скрыт внутриобъекта;

4 / 1

Page 5: Принципы объектно-ориентированного проектирования

Закон Деметера• метод может вызывать другие методы своего класса;• метод может вызывать методы своих свойств (но несвойств своих свойств);

• метод может вызывать методы параметров;• метод может вызывать методы своих локальных объектов;• метод не может вызывать методы глобального объекта (ноего можно передать как параметр);

• метод не может использовать цепочку вызовов,возвращающих промежуточные объекты других классов.

Не абсолютная истина, но желательно учитывать.

5 / 1

Page 6: Принципы объектно-ориентированного проектирования

НаследованиеПлюсы:

• повторное использование кода;• полиморфизм.

Минусы:

• изменения в базовом классе отражаются на всейиерархии;

• большое количество уровней наследования можетсущественно затруднить разработку.

Избыточное наследование — частая проблема6 / 1

Page 7: Принципы объектно-ориентированного проектирования

Композицияinterface Feature1 {

public function m1();}interface Feature2 {

public function m2();}class Object {

private $f1, f2;

public function __construct(Feature1 $f1, Feature2 $f2) {$this->f1 = f1;$this->f2 = f2;

}public function m1() { return $this->f1->m1(); }public function m2() { return $this->f2->m2(); }

}

7 / 1

Page 8: Принципы объектно-ориентированного проектирования

Композиция: реализация• в 5.3 объекты-свойства и делегирование вызовов;• можно уменьшить количество кода за счет magic methods;• в 5.4 поддержка на уровне языка:

trait Feature1 {public function m1() {...}

}trait Feature2 {

public function m2() {...}}class Object use Feature1, Feature2 {

...}

8 / 1

Page 9: Принципы объектно-ориентированного проектирования

Базовые принципы

S. O. L. I. D.

SRP Single Responsibility PrincipleOCP Open/Closed PrincipleLSP Liskov Substitution PrincipleISP Interface Segregation PrincipleDIP Dependency Inversion Principle

9 / 1

Page 10: Принципы объектно-ориентированного проектирования

Принцип единственнойобязанности

SRP Single ResponsibilityPrinciple

Класс должен нести ответственность завыполнение одной задачи.

10 / 1

Page 11: Принципы объектно-ориентированного проектирования

SRP: нарушения

Сложный класс, пытающийся делать несколько делодновременно:

• работа с данными разных уровней абстракций;• большое количество зависимостей;• низкая связность между отдельными свойствами объектов;

В пределе получаем «God Class», вся функциональность водном классе.

11 / 1

Page 12: Принципы объектно-ориентированного проектирования

Нарушение SRP

class User extends ActiveRecord {

// Работа с сущностью: одна ответственность.public function setName($name) {...}public function getName() {...}public function setGroup(Group $group) {...}

// Хранение сущности: вторая ответственность,// изменение способа хранение — переписывание класса.public function save() {...}public function delete() {...}

}

2 / 7

Page 13: Принципы объектно-ориентированного проектирования

SRP: исправляемclass User extends Entity {

public function setName($name) {...}public function getName() {...}public function setGroup(Group $group) {...}

}

class UserMapper extends SQLMapper {

public function save(User $user) {...}public function delete(User $user) {...}

}

13 / 1

Page 14: Принципы объектно-ориентированного проектирования

SRP: методы

Принцип SRP применим и к методам:

• метод должен реализовывать единственнуюфункциональность;

• чем меньше метод, тем его проще понимать и отлаживать;• именование методов очень важно, в идеале код долженчитаться как текст, описывающий то, что в нем происходит.

Методы должны быть компактными, если код метода невмещается на экран — значит вы что-то делаете не так.

14 / 1

Page 15: Принципы объектно-ориентированного проектирования

Связность и связанность

Cohesion (связность) насколько сильно связаныи сонаправлены обязанности модуля

Coupling (связанность) насколько сильномодуль зависит от других модулей

Нужно стремиться к слабойсвязанности, но сильной связности :)

15 / 1

Page 16: Принципы объектно-ориентированного проектирования

Принципоткрытости/закрытости

OCP Open/Closed Principle

Программные сущности должны быть открытыдля расширения, но закрыты для изменения.

16 / 1

Page 17: Принципы объектно-ориентированного проектирования

Нарушение OCP

class Logger {

public function log($message) {switch ($this->type) {

case ’syslog’:return $this->logToSyslog($message);

case ’text’:return $this->logToFile($message);

// и так далее}

}}

Добавляем очередной вид логирования — меняем класс.

3 / 7

Page 18: Принципы объектно-ориентированного проектирования

OCP: исправляем

class Logger {public function log($message) {

foreach ($this->transports as $t) {$t->log($message);

}}

}

abstract class LogTransport {abstract public function log($message);

}

18 / 1

Page 19: Принципы объектно-ориентированного проектирования

OCP: что делатьЧем меньше кода нужно менять для добавленияфункциональности, тем лучше:

• наследование;• композиция + стратегии реализации в отдельных классах.

Иногда выгоднее не использовать, если увеличение количествавариантов маловероятно: арифметические и логическиедействия, HTTP-методы, операторы SQL и т.д.

Больше классов не значит сложнее!

19 / 1

Page 20: Принципы объектно-ориентированного проектирования

Принцип подстановкиЛисков

LSP Liskov Substitution Principle

Объекты могут быть заменены объектамипроизводных классов без изменения свойствпрограммы.

20 / 1

Page 21: Принципы объектно-ориентированного проектирования

Нарушение LSP

class Product {public function getName() {...}public function getAuthor() {...}

}

class Book extends Product {...}class Movie extends Product {

public function getAuthor() {// у Movie нет автора, что делать?

}}

4 / 7

Page 22: Принципы объектно-ориентированного проектирования

Нарушение LSP<#small_begin |||>

// после добавления увеличивается countclass List {

private $items = array();public function add($item) { $this->items[] = $item; }public function count($item) {

return count($this->items);}

}

// после добавления не увеличивается countclass UniqueList extends List {

public function add($item) {if (array_find($item, $this->items) === false) {

$this->items[] = $item;}

}

<#small_end |||>

5 / 7

Page 23: Принципы объектно-ориентированного проектирования

Принцип разделенияинтерфейса

ISP Interface Separation Principle

Классы не должны зависеть от интерфейсов,которые они не используют.

Несколько специализированных интерфейсовлучше, чем один общий.

23 / 1

Page 24: Принципы объектно-ориентированного проектирования

Нарушение ISP

class Contact {public function getEmail() { ... }public function getPhoneNumber() { ... }

}

class Mailer {public function sendTo(Contact $contact) {...}

}

class Dialer {public function call(Contact $contact) {...}

}

6 / 7

Page 25: Принципы объектно-ориентированного проектирования

Исправляем нарушение ISPinterface Emailable {

public function getEmail();}

interface Diallable {public function getPhoneNumber();

}

class Mailer {public function sendTo(Emailable$contact) {...}

}

class Dialer {public function call(Diallable $contact) {...}

}

25 / 1

Page 26: Принципы объектно-ориентированного проектирования

Принцип инверсиизависимостей

DIP Dependency Inversion Principle

Высокоуровневые модули должны зависеть неот низкоуровневых, а от абстракций.

Абстракции не должны зависеть от деталей.Детали должны зависеть от абстракций.

26 / 1

Page 27: Принципы объектно-ориентированного проектирования

Нарушение DIP

// Что делать, если мы хотим читать конфигурацию из базы?class Configuration {

private $storage;private $data;

public function __construct() {$this->storage = new FileStorage(’config.json’);

}

public function load()$this->data = $this->storage->load();

}}

7 / 7

Page 28: Принципы объектно-ориентированного проектирования

Исправляем нарушение DIPinterface StorageInterface {

public function load();}

class FileStorage implements StorageInterface {...}class SQLStorage implemens StorageInterface {...}

class Configuration {private $storage;private $data;

// Constructor Injection:public function __construct(StorageInterface $storage) {

$this->storage = $storage;}

}

28 / 1

Page 29: Принципы объектно-ориентированного проектирования

DIP: нарушения

• использование new;• использование registry-объектов (теперь наш класс жесткопривязан к registry и у нас все та же проблема);

• использование Singletone;

Проблемы:

• невозможность расширения без нарушения OCP;• невозможность написания тестов.

29 / 1

Page 30: Принципы объектно-ориентированного проектирования

DIP: что делать

• не создавать зависимые объекты при создании класса(если это не узкоспециализированные вспомогательныеклассы);

• делить приложение на отдельные слои, слабо связанныедруг с другом;

• использовать интерфейсы для типизации зависимостей;• не использовать глобальные переменные и ихобъектно-ориентированные варианты;

• использовать DI-контейнер.

30 / 1

Page 31: Принципы объектно-ориентированного проектирования

Самый главный принцип

Думайте и используйтездравый смысл.

31 / 1