Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.
S.O.L.I.D.
Принципы
объектного
проектирования
классов
Обо мне
Alexander Nemanov
alexander@asoft4web.com
Skype: asoft4web
FB:
https://www.facebook.com/alexander.nemanov
S.O.L.I.D. - принципы
1. Принцип единственности ответственности (SRP: Single Responsibility
Principle)
2. Принцип открытос...
SRP - Принцип единственности ответственности
Формулировка:
Не должно быть больше одной причины для изменения класса
Каждый...
SRP - Принцип единственности ответственности
class Order
{
public function calculateTotalSum() {/*...*/}
public function g...
SRP - Принцип единственности ответственности
3 различный типов задач (3-и причины для изменения одного класса):
• работа с...
SRP - Принцип единственности ответственности
class Order {
public function calculateTotalSum() {/*...*/}
public function g...
SRP - Принцип единственности ответственности
Проблема: Задача валидации данных
Первое решение:
class Product {
public func...
OCP - Принцип открытости/закрытости
Формулировка:
• программные сущности (классы, модули, функции и т.д.) должны быть
откр...
OCP - Принцип открытости/закрытости
class Logger {
public function Log($logText) { /* Save to file */ }
}
class SmtpMailer...
OCP - Принцип открытости/закрытости
class DbLogger {
public function Log($logText) { /* Save to Db */ }
}
class SmtpMailer...
OCP - Принцип открытости/закрытости
interface LoggerInterface {
public function Log($logText);
}
class Logger implements L...
OCP - Принцип открытости/закрытости
class SmtpMailer {
private $logger;
public function __construct(LoggerInterface $logge...
OCP - Принцип открытости/закрытости
Конкретизируя классы методом instanceof мы должны сразу понять, что наш
код начал "поп...
OCP - Принцип открытости/закрытости
1. "Открыт для расширения":
поведение может быть расширено
путем добавления новых объе...
LSP - Принцип замещения Лисков
Формулировка №1: eсли для каждого объекта o1 типа S существует объект
o2 типа T, который дл...
LSP - Принцип замещения Лисков
Формулировка №1: eсли для каждого объекта o1 типа S существует объект
o2 типа T, который дл...
LSP - Принцип замещения Лисков
Поведение наследуемых классов не должно противоречить поведению,
заданному базовым классом,...
LSP - Принцип замещения Лисков
• Следовать этому принципу очень важно при проектировании новых типов
с использованием насл...
ISP - Принцип разделения интерфейса
Формулировка: клиенты не должны зависеть от методов, которые они не
используют
Как и п...
ISP - Принцип разделения интерфейса
interface IItem {
public function applyDiscount($discount);
public function applyPromo...
ISP - Принцип разделения интерфейса
interface IItem {
public function setCondition($condition);
public function setPrice($...
ISP - Принцип разделения интерфейса
class Book implemets IItem, IDiscountable {
public function setCondition($condition){/...
DIP - Принцип инверсии зависимости
Формулировка:
• Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Об...
DIP - Принцип инверсии зависимости
class OrderProcess {
public function CalculeteTotal(Order $order) {
$itemTotal = $order...
DIP - Принцип инверсии зависимости
Причина, по которой проекты "стареют", заключается в том, что у
разработчиков нет возмо...
DIP - Принцип инверсии зависимости
Перечислим все обязанности, которые выполняет класс OrderProcessor:
• Знает, как вычисл...
DIP - Принцип инверсии зависимости
interface DiscountCalculatorInterface {
public function calculateDiscount(Order $order)...
DIP - Принцип инверсии зависимости
class OrderProcess {
/** @var DiscountCalculatorInterface */
private $discountCalculato...
DIP - Принцип инверсии зависимости
OrderProcess
DiscountCalculator
DiscountCalculatorInterface TaxStrategyInterface
USTaxS...
DIP - Принцип инверсии зависимости
Принцип обращения зависимости - это очень мощный
инструмент, который в сочетании с друг...
?
SOLID
Próxima SlideShare
Cargando en…5
×

SOLID

1.141 visualizaciones

Publicado el

S.O.L.I.D. - Принципы объектного проектирования классов

Publicado en: Tecnología
  • Sé el primero en comentar

SOLID

  1. 1. S.O.L.I.D. Принципы объектного проектирования классов
  2. 2. Обо мне Alexander Nemanov alexander@asoft4web.com Skype: asoft4web FB: https://www.facebook.com/alexander.nemanov
  3. 3. S.O.L.I.D. - принципы 1. Принцип единственности ответственности (SRP: Single Responsibility Principle) 2. Принцип открытости/закрытости (OCP: Open/Closed Principle) 3. Принцип подстановки Лисков (LSP: Liskov Substitution Principle) 4. Принцип разделения интерфейса (ISP: Interface Segregation Principle) 5. Принцип инверсии зависимостей (DIP: Dependency Inversion Principle)
  4. 4. SRP - Принцип единственности ответственности Формулировка: Не должно быть больше одной причины для изменения класса Каждый объект должен иметь одну обязанность и эта обязанность должна быть полностью инкапсулирована в класс.
  5. 5. SRP - Принцип единственности ответственности class Order { public function calculateTotalSum() {/*...*/} public function getItems() {/*...*/} public function getItemCount() {/*...*/} public function addItem($item) {/*...*/} public function deleteItem($item) {/*...*/} public function printOrder() {/*...*/} public function showOrder() {/*...*/} public function load() {/*...*/} public function save() {/*...*/} public function update() {/*...*/} public function delete() {/*...*/} }
  6. 6. SRP - Принцип единственности ответственности 3 различный типов задач (3-и причины для изменения одного класса): • работа с самим заказом • отображение заказа • работа с хранилищем данных Решение: Сделать отдельные классы. Чтобы каждый класс занимается своей конкретной задачей и для каждого класса была только 1 причина для его изменения.
  7. 7. SRP - Принцип единственности ответственности class Order { public function calculateTotalSum() {/*...*/} public function getItems() {/*...*/} public function getItemCount() {/*...*/} public function addItem($item) {/*...*/} public function deleteItem($item) {/*...*/} } class OrderRepository { public function load($orderID){/*...*/} public function save($order){/*...*/} public function update($order){/*...*/} public function delete($order){/*...*/} } class OrderViewer { public function printOrder($order){/*...*/} public function showOrder($order){/*...*/} }
  8. 8. SRP - Принцип единственности ответственности Проблема: Задача валидации данных Первое решение: class Product { public function isValid() { return $this->price > 0; } } Решение: отдать ответственность за валидацию данных продукта другому объекту. Причем надо сделать так, чтобы сам объект продукта не зависел от конкретной реализации его валидатора. $validator = $this->get('validator'); $errors = $validator->validate($product);
  9. 9. OCP - Принцип открытости/закрытости Формулировка: • программные сущности (классы, модули, функции и т.д.) должны быть открыты для расширения, но закрыты для изменения Принцип открытости/закрытость дает понимание того, как оставаться достаточно гибкими в условиях постоянно меняющихся требований. Все классы, функции и т.д. должны проектироваться так, чтобы для изменения их поведения, нам не нужно было изменять их исходный код.
  10. 10. OCP - Принцип открытости/закрытости class Logger { public function Log($logText) { /* Save to file */ } } class SmtpMailer { private $logger; public function __construct() { $this->logger = new Logger(); } public function sendMessage($message) { // Send // Save to log $this->logger->Log($message); } }
  11. 11. OCP - Принцип открытости/закрытости class DbLogger { public function Log($logText) { /* Save to Db */ } } class SmtpMailer { private $logger; public function __construct() { $this->logger = new DbLogger(); } public function sendMessage($message) { // Send // Save to log $this->logger->Log($message); } }
  12. 12. OCP - Принцип открытости/закрытости interface LoggerInterface { public function Log($logText); } class Logger implements LoggerInterface { public function Log($logText) { /* Save to file */ } } class DbLogger implements LoggerInterface { public function Log($logText) { /* Save to file */ } }
  13. 13. OCP - Принцип открытости/закрытости class SmtpMailer { private $logger; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } public function sendMessage($message) { // Send // Save to log $this->logger->Log($message); } }
  14. 14. OCP - Принцип открытости/закрытости Конкретизируя классы методом instanceof мы должны сразу понять, что наш код начал "попахивать": abstract class BaseEntity { } class AcountEntity extends BaseEntity { } class RoleEntity extends BaseEntity { } class Repository { public function save(BaseEntity $entiry) { if ($entiry instanceof AcountEntity) { // ... } else if ($entiry instanceof RoleEntity) { // ... } } }
  15. 15. OCP - Принцип открытости/закрытости 1. "Открыт для расширения": поведение может быть расширено путем добавления новых объектов, реализующих новые аспекты поведения; 2. "Закрыт для модификации": в результате расширения поведения исходный код объекта не может быть изменен.
  16. 16. LSP - Принцип замещения Лисков Формулировка №1: eсли для каждого объекта o1 типа S существует объект o2 типа T, который для всех программ P определен в терминах T, то поведение P не изменится, если o1 заменить на o2 при условии, что S является подтипом T.
  17. 17. LSP - Принцип замещения Лисков Формулировка №1: eсли для каждого объекта o1 типа S существует объект o2 типа T, который для всех программ P определен в терминах T, то поведение P не изменится, если o1 заменить на o2 при условии, что S является подтипом T. Формулировка №2: подтипы должны быть заменяемы базовыми типами.
  18. 18. LSP - Принцип замещения Лисков Поведение наследуемых классов не должно противоречить поведению, заданному базовым классом, то есть поведение наследуемых классов должно быть ожидаемым для кода, использующего переменную базового типа. interface CollectionInterface { public function get($index); public function count(); } class MyCollection implements CollectionInterface { public function get($index) { } public function count() {} } $myCollection = new MyCollection(); if (1 == $myCollection->count()) { $firstItem = $collection->get(0); // Exception, null }
  19. 19. LSP - Принцип замещения Лисков • Следовать этому принципу очень важно при проектировании новых типов с использованием наследования. • Этот принцип предупреждает разработчика о том, что изменение унаследованного производным типом поведения очень рискованно. Пример рассмотрен в книге Роберта Мартина «Быстрая разработка программ» в разделе «Принцип подстановки Лискоу. Реальный пример»
  20. 20. ISP - Принцип разделения интерфейса Формулировка: клиенты не должны зависеть от методов, которые они не используют Как и при использовании других принципов проектирования классов мы пытаемся избавиться от ненужных зависимостей в коде, сделать код легко читаемым и легко изменяемым.
  21. 21. ISP - Принцип разделения интерфейса interface IItem { public function applyDiscount($discount); public function applyPromocode($promocode); public function setColor($color); public function setSize($size); public function setCondition($condition); public function setPrice($price); }
  22. 22. ISP - Принцип разделения интерфейса interface IItem { public function setCondition($condition); public function setPrice($price); } interface IClothes { public function setColor($color); public function setSize($size); public function setMaterial($material); } interface IDiscountable { public function applyDiscount($discount); public function applyPromocode($promocode); }
  23. 23. ISP - Принцип разделения интерфейса class Book implemets IItem, IDiscountable { public function setCondition($condition){/*...*/} public function setPrice($price){/*...*/} public function applyDiscount($discount){/*...*/} public function applyPromocode($promocode){/*...*/} } class KidsClothes implemets IItem, IClothes { public function setCondition($condition){/*...*/} public function setPrice($price){/*...*/} public function setColor($color){/*...*/} public function setSize($size){/*...*/} public function setMaterial($material){/*...*/} }
  24. 24. DIP - Принцип инверсии зависимости Формулировка: • Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракции. • Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
  25. 25. DIP - Принцип инверсии зависимости class OrderProcess { public function CalculeteTotal(Order $order) { $itemTotal = $order->getItemTotal(); $discountCalculator = new DiscountCalculator(); $discountAmount = $discountCalculator->calculateDiscount($order); $taxAmount = 0; if($order->getCountry() == "US") { $taxAmount = $this->getTaxAmount($order); } elseif ($order->getCountry() == "UK") { $taxAmount = $this->getVatAmount($order); } return $itemTotal - $discountAmount + $taxAmount; } private function getTaxAmount(Order $order) { } private function getVatAmount(Order $order) { } }
  26. 26. DIP - Принцип инверсии зависимости Причина, по которой проекты "стареют", заключается в том, что у разработчиков нет возможности безболезненно менять код каких-то компонентов без боязни нарушить работу других. Дизайн таких систем можно охарактеризовать следующими признаками: • Жесткость - изменение одной части кода затрагивает слишком много других частей; • Хрупкость - даже незначительное изменение в коде может привести к совершенно неожиданным проблемам; • Неподвижность - никакая из частей приложения не может быть легко выделена и повторно использована.
  27. 27. DIP - Принцип инверсии зависимости Перечислим все обязанности, которые выполняет класс OrderProcessor: • Знает, как вычислить сумму заказа; • Знает, как и каким калькулятором вычислить сумму скидки; • Знает, что означают коды стран; • Знает, каким образом вычислить сумму налога для той или иной страны; • Знает формулу, по которой из всех слагаемых вычисляется стоимость заказа. OrderProcess DiscountCalculator
  28. 28. DIP - Принцип инверсии зависимости interface DiscountCalculatorInterface { public function calculateDiscount(Order $order); } class DiscountCalculator implements DiscountCalculatorInterface { public function calculateDiscount(Order $order) { } } interface TaxStrategyInterface { public function getTaxAmount(Order $order); } class USTaxStarategy implements TaxStrategyInterface { public function getTaxAmount(Order $order) { } } class UKTaxStarategy implements TaxStrategyInterface { public function getTaxAmount(Order $order) { } }`
  29. 29. DIP - Принцип инверсии зависимости class OrderProcess { /** @var DiscountCalculatorInterface */ private $discountCalculator; /** @var TaxStrategyInterface */ private $taxStarategy; public function __construct(DiscountCalculatorInterface $discountCalculator, TaxStrategyInterface $taxStarategy) { $this->discountCalculator = $discountCalculator; $this->taxStarategy = $taxStarategy; } public function CalculeteTotal(Order $order) { $itemTotal = $order->getItemTotal(); $discountAmount = $this->discountCalculator->calculateDiscount($order); $taxAmount = $this->taxStarategy->getTaxAmount($order); return $itemTotal - $discountAmount + $taxAmount; } }
  30. 30. DIP - Принцип инверсии зависимости OrderProcess DiscountCalculator DiscountCalculatorInterface TaxStrategyInterface USTaxStarategy UKTaxStarategy
  31. 31. DIP - Принцип инверсии зависимости Принцип обращения зависимости - это очень мощный инструмент, который в сочетании с другими SOLID- принципами позволяет разрабатывать дизайн систем так же легко, как если бы он собирался из конструктора LEGO.
  32. 32. ?

×