SlideShare ist ein Scribd-Unternehmen logo
1 von 29
S.O.L.I.D Расшифруем: S - Single responsibility principle (SRP) O - Open/closed principle (OCP) L - Liskov substitution principle (LSP) I - Interface segregation principle (ISP) D - Dependency inversion principle (DIP)
Зачем эти правила? Помогают построить архитектуру приложения, которое со временем возможно будет проще (дешевле) поддерживать и развивать. Помогают писать повторно используемый код.
Принцип единственности ответственности (SRP) Не должно быть больше одной причины для изменения класса. Почему? Потому что это ведет к хрупкости дизайна (пишем один функционал - ”отваливается” другой).
Высшая раса нарушающая SRP – это God Object Что такое ”плохо”:
Борьба с высшей расой Лучше так:
Принцип открытости/закрытости (OCP) Программные сущности (классы, модули, функции)  должны быть открыты для расширения, но закрыты для изменения. Почему? Потому что это позволяет быстро и безболезненно реагировать на изменение бизнес-требований.
class Logger { public function log($text) { // Сохраняем текст в лог (лог у нас будет храниться в файлах) } } class Product { private $_logger; public function __construct() { $this->_logger = new Logger(); } /* Продать товар */ public function sale() { // … продаем товар // Записываем дату продажи в лог $this->_logger->log('Sale time: '.  time()); } } Чем плох этот код?
Лог продаж в файлах?! Это же отстой! Изменение требований: лог надо хранить в БД class DBLogger { public function log($text) { // Сохраняем что-то в лог (лог у нас будет храниться в БД) } } class Product { private $_logger; public function __construct() { // Меняем класс Product, чтоб поменять логер (помните про SRP?) $this->_logger = new DBLogger(); } /* Продать товар*/ public function sale() { // Продаем товар // ... // Записываем дату продажи в лог $this->_logger->log('Sale time: '.  time()); } }
Готовимся к борьбе с изменениями требований (а не к борьбе с менеджерами) interface ILogger { public function log($text); } class Logger implements ILogger { public function log($text) { // Сохраняем что-то в лог (лог у нас будет храниться в файлах) } } class DBLogger implements ILogger { public function log($text) { // Сохраняем что-то в лог (лог у нас будет храниться в БД) } } class Product { private $_logger; public function __construct(ILogger $logger) { $this->_logger = $logger; } /* Продать товар */ public function sale() { // Продаем товар // ... // Записываем дату продажи в лог $this->_logger->log('Sale time: '.  time()); } }
Принцип подстановки Барбары Лисков (LSP) Поведение наследуемых классов не должно противоречить поведению, заданному базовым классом. Почему? Потому что клиентский код начинает считать производный класс разновидностью базового, и возможно появление кода, явно использующего этот факт.
Байка про утку и батарейки
Ударим кодом по уткам (базовый класс) /* Определим базовую утку */ abstract class Duck { private $_batteryStatus = 100; // Стстус заряда батареек утки (%) private $_steps = 0; // Количество шагов пройденных уткой (шт.) public function getBatteryStatus() { return $this->_batteryStatus; } public function setBatteryStatus($value) { $this->_batteryStatus = $value; } public function getSteps() { return $this->_steps; } public function setSteps($value) { $this->_steps = $value; } // Эти методы абстрактные (разные утки крякают и двигаются по-своему) abstract public function move(); abstract public function quack(); }
Утки на батарейках (Америка, Китай) /* Американская утка на батарейках */ class AmericanDuck extends Duck { public function move() { $this->setSteps($this->getSteps() + 1); // Утка шагает $this->setBatteryStatus($this->getBatteryStatus() - 20); // Батарейки садятся echo "Я прошагала {$this->getSteps()} шагов (заряд батарейки: {$this->getBatteryStatus()}%) "; } public function quack() { echo "Здравствуйте, я Американская утка! "; } } /* Китайская утка на батарейках */ class ChinaDuck extends Duck { public function move() { $this->setSteps($this->getSteps() + 1); // Утка шагает $this->setBatteryStatus($this->getBatteryStatus() - 10); // Батарейки садятся (но не так быстро) echo "Я прошагала {$this->getSteps()} шагов (заряд батарейки: {$this->getBatteryStatus()}%) "; } public function quack() { echo "Здравствуйте, я Китайский утка, я плохо говорить по-русски, но я уметь много шагать! "; } }
Клиентский код использования уток // Имеем список уток $duckList = array(new AmericanDuck(), new ChinaDuck()); // Просим всех уток по очереди представиться и походить foreach($duckList as $duck) { $duck->quack(); // Представимся while ($duck->getBatteryStatus() > 0) { // Утка должна шагать, пока не сядут батарейки $duck->move(); sleep(1); } echo ""; }
Появилась возожность юзать живую утку! /* Живая утка. Её особенность в том, что у нее нет батареек и она шагает сколько хочет */ class BrainyDuck extends Duck { public function move() { $this->setSteps($this->getSteps() + 1); // Утка шагает echo "Я прошагала {$this->getSteps()} шагов "; } public function quack() { echo "Здравствуйте, я живая утка с мозгом! "; } public function getBatteryStatus() { throw new Exception('Сума сошел? Какие батарейки, я живая!'); } public function setBatteryStatus() { throw new Exception('Сума сошел? Какие батарейки, я живая!'); } }
Клиентский код и Fail исползования уток // Имеем список уток $duckList = array(new AmericanDuck(), new ChinaDuck(), new BrainyDuck()); // Просим всех уток по очереди представиться и походить foreach($duckList as $duck) { $duck->quack(); // Представимся while ($duck->getBatteryStatus() > 0) { // Утка должна шагать, пока не сядут батарейки $duck->move(); sleep(1); } echo ""; }
Принцип разделения интерфейса (ISP) Клиенты не должны зависеть от методов, которые они не используют. Почему? Если мы определим большой универсальный интерфейс, тогда в наследниках возможно появление множества заглушек, а соответственно, много лишнего кода, который неудобно поддерживать.
Делаем трансформера  (пока что все хорошо) interface IMegaTrsansformer { public function transformToCar(); public function transformToShip(); public function transformToPlane(); } class MegaTrsansformer implements IMegaTrsansformer { public function transformToCar() { echo 'Я преобразовался и стал спортивной машиной!'; } public function transformToShip() { echo 'Я преобразовался и стал сверхбыстрым катером!'; } public function transformToPlane() { echo 'Я преобразовался и стал истребителем!'; } }
А теперь нужно сделать менее крутых трансформеров (в каждом из них теперь костыли) class TaxiTrsansformer implements IMegaTrsansformer { public function transformToCar() { echo 'Я преобразовался и стал такси!'; } public function transformToShip() { throw new Exception('Данная трансформация не поддерживается'); } public function transformToPlane() { throw new Exception('Данная трансформация не поддерживается'); } } class StelthTrsansformer implements IMegaTrsansformer { public function transformToCar() { throw new Exception('Данная трансформация не поддерживается'); } public function transformToShip() { throw new Exception('Данная трансформация не поддерживается'); } public function transformToPlane() { echo 'Я преобразовался и стал стелсом!'; } } class IcebreakerTrsansformer implements IMegaTrsansformer { public function transformToCar() { throw new Exception('Данная трансформация не поддерживается'); } public function transformToShip() { echo 'Я преобразовался и стал ледоколом!'; } public function transformToPlane() { throw new Exception('Данная трансформация не поддерживается'); } }
Лучше иметь такой набор интерфейсов interface ICarTrsansformer { public function transformToCar(); } interface IShipTrsansformer { public function transformToShip(); } interface IPlaneTrsansformer { public function transformToPlane(); }
И такой набор классов class MegaTrsansformer implements ICarTrsansformer, IShipTrsansformer, IPlaneTrsansformer { public function transformToCar() { echo 'Я преобразовался и стал спортивной машиной!'; } public function transformToShip() { echo 'Я преобразовался и стал сверхбыстрым катером!'; } public function transformToPlane() { echo 'Я преобразовался и стал истребителем!'; } } class TaxiTrsansformer implements ICarTrsansformer { public function transformToCar() { echo 'Я преобразовался и стал такси!'; } } class StelthTrsansformer implements IPlaneTrsansformer { public function transformToPlane() { echo 'Я преобразовался и стал стелсом!'; } } class IcebreakerTrsansformer implements IShipTrsansformer { public function transformToShip() { echo 'Я преобразовался и стал ледоколом!'; } }
Принцип инверсии зависимостей (DIP) ,[object Object]
Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций
Анатомия зависимостей (X зависит от Y + циклическая зависимость) Зависимости бывают: - Прямые; - Транзитивные; - Циклические.
Зависимость модуля верхннго уровня от модулей нижнего уровня class siteMapBilder { private $_dataStorage; private $_webGrabber; public function __construct() { $this->_dataStorage = new FileDataStorage(); $this->_webGrabber = new CurlWebGrabber(); } // ... Здесь какие-то методы для построения карты сайта }
Освобождаем SiteMapBuilder от  зависимостей (инвертируем зависимости) class siteMapBilder { private $_dataStorage; private $_webGrabber; public function __construct(WebGrabber $dataStorage, DataStorage $webGrabber) { $this->_dataStorage = $dataStorage; $this->_webGrabber = $webGrabber; } // ... Здесь какие-то методы для построения карты сайта }
«... любые хорошо структурированные объектно-ориентированные архитектуры имеют четко определенные слои, каждый из которых поддерживает некоторый компактный набор служб с помошью хорошо определенного и контролируемого интерфейса» Г. Буч Разделение архитектуры по слоям
Усовершенствованное разделение архитектуры по слоям  Здесь мы избавились не только от транзитивной зависимости между TopLayer и DeepLayer, но и  от прямых зависимостей
Спасибо за внимание Вопросы?

Weitere ähnliche Inhalte

Was ist angesagt?

C++ STL & Qt. Занятие 03.
C++ STL & Qt. Занятие 03.C++ STL & Qt. Занятие 03.
C++ STL & Qt. Занятие 03.Igor Shkulipa
 
Классы и объекты в Java
Классы и объекты в JavaКлассы и объекты в Java
Классы и объекты в Javametaform
 
Классы и объекты в Java
Классы и объекты в JavaКлассы и объекты в Java
Классы и объекты в Javametaform
 
Работа с БД в Java
Работа с БД в JavaРабота с БД в Java
Работа с БД в Javametaform
 
Глава 3: примитивные типы и операции с ними в Java
Глава 3: примитивные типы и операции с ними в JavaГлава 3: примитивные типы и операции с ними в Java
Глава 3: примитивные типы и операции с ними в Javametaform
 
C++ Базовый. Занятие 15.
C++ Базовый. Занятие 15.C++ Базовый. Занятие 15.
C++ Базовый. Занятие 15.Igor Shkulipa
 
C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.Igor Shkulipa
 
C# Desktop. Занятие 07.
C# Desktop. Занятие 07.C# Desktop. Занятие 07.
C# Desktop. Занятие 07.Igor Shkulipa
 
JavaScript Базовый. Занятие 03.
JavaScript Базовый. Занятие 03.JavaScript Базовый. Занятие 03.
JavaScript Базовый. Занятие 03.Igor Shkulipa
 
C++ STL & Qt. Занятие 08.
C++ STL & Qt. Занятие 08.C++ STL & Qt. Занятие 08.
C++ STL & Qt. Занятие 08.Igor Shkulipa
 
Java Core. Lecture# 3. Part# 3. Multithreading.
Java Core. Lecture# 3. Part# 3. Multithreading.Java Core. Lecture# 3. Part# 3. Multithreading.
Java Core. Lecture# 3. Part# 3. Multithreading.Anton Moiseenko
 
JavaScript Базовый. Занятие 02.
JavaScript Базовый. Занятие 02.JavaScript Базовый. Занятие 02.
JavaScript Базовый. Занятие 02.Igor Shkulipa
 
C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.Igor Shkulipa
 
принципы ооп и программирование классов в C#
принципы ооп и программирование классов в C#принципы ооп и программирование классов в C#
принципы ооп и программирование классов в C#bolevik
 
работа с потоками ввода вывода
работа с потоками ввода выводаработа с потоками ввода вывода
работа с потоками ввода выводаmetaform
 
C++ STL & Qt. Занятие 07.
C++ STL & Qt. Занятие 07.C++ STL & Qt. Занятие 07.
C++ STL & Qt. Занятие 07.Igor Shkulipa
 
Java Core. Lecture# 2. Classes & objects.
Java Core. Lecture# 2. Classes & objects.Java Core. Lecture# 2. Classes & objects.
Java Core. Lecture# 2. Classes & objects.Anton Moiseenko
 
C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.Igor Shkulipa
 

Was ist angesagt? (20)

C++ STL & Qt. Занятие 03.
C++ STL & Qt. Занятие 03.C++ STL & Qt. Занятие 03.
C++ STL & Qt. Занятие 03.
 
Классы и объекты в Java
Классы и объекты в JavaКлассы и объекты в Java
Классы и объекты в Java
 
Классы и объекты в Java
Классы и объекты в JavaКлассы и объекты в Java
Классы и объекты в Java
 
Работа с БД в Java
Работа с БД в JavaРабота с БД в Java
Работа с БД в Java
 
Bytecode
BytecodeBytecode
Bytecode
 
Глава 3: примитивные типы и операции с ними в Java
Глава 3: примитивные типы и операции с ними в JavaГлава 3: примитивные типы и операции с ними в Java
Глава 3: примитивные типы и операции с ними в Java
 
Stream API
Stream APIStream API
Stream API
 
C++ Базовый. Занятие 15.
C++ Базовый. Занятие 15.C++ Базовый. Занятие 15.
C++ Базовый. Занятие 15.
 
C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.
 
C# Desktop. Занятие 07.
C# Desktop. Занятие 07.C# Desktop. Занятие 07.
C# Desktop. Занятие 07.
 
JavaScript Базовый. Занятие 03.
JavaScript Базовый. Занятие 03.JavaScript Базовый. Занятие 03.
JavaScript Базовый. Занятие 03.
 
C++ STL & Qt. Занятие 08.
C++ STL & Qt. Занятие 08.C++ STL & Qt. Занятие 08.
C++ STL & Qt. Занятие 08.
 
Java Core. Lecture# 3. Part# 3. Multithreading.
Java Core. Lecture# 3. Part# 3. Multithreading.Java Core. Lecture# 3. Part# 3. Multithreading.
Java Core. Lecture# 3. Part# 3. Multithreading.
 
JavaScript Базовый. Занятие 02.
JavaScript Базовый. Занятие 02.JavaScript Базовый. Занятие 02.
JavaScript Базовый. Занятие 02.
 
C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.
 
принципы ооп и программирование классов в C#
принципы ооп и программирование классов в C#принципы ооп и программирование классов в C#
принципы ооп и программирование классов в C#
 
работа с потоками ввода вывода
работа с потоками ввода выводаработа с потоками ввода вывода
работа с потоками ввода вывода
 
C++ STL & Qt. Занятие 07.
C++ STL & Qt. Занятие 07.C++ STL & Qt. Занятие 07.
C++ STL & Qt. Занятие 07.
 
Java Core. Lecture# 2. Classes & objects.
Java Core. Lecture# 2. Classes & objects.Java Core. Lecture# 2. Classes & objects.
Java Core. Lecture# 2. Classes & objects.
 
C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.
 

Andere mochten auch

SOLID & GRASP
SOLID & GRASPSOLID & GRASP
SOLID & GRASPdevel123
 
Как писать красивый код или основы SOLID
Как писать красивый код или основы SOLIDКак писать красивый код или основы SOLID
Как писать красивый код или основы SOLIDPavel Tsukanov
 
Mvc, mvp and mvvm: A comparison of architectural patterns
Mvc, mvp and mvvm: A comparison of architectural patternsMvc, mvp and mvvm: A comparison of architectural patterns
Mvc, mvp and mvvm: A comparison of architectural patternsIvan Dyachenko
 
Viper - чистая архитектура iOS-приложения (И. Чирков)
Viper - чистая архитектура iOS-приложения (И. Чирков)Viper - чистая архитектура iOS-приложения (И. Чирков)
Viper - чистая архитектура iOS-приложения (И. Чирков)65apps
 
iOS-02-Паттерны ООП
iOS-02-Паттерны ООПiOS-02-Паттерны ООП
iOS-02-Паттерны ООПNoveo
 
#MBLTdev: Мобильная реклама ВКонтакте
#MBLTdev: Мобильная реклама ВКонтакте#MBLTdev: Мобильная реклама ВКонтакте
#MBLTdev: Мобильная реклама ВКонтактеe-Legion
 
#MBLTdev: Опыт использования MVVM в реальных проектах
#MBLTdev: Опыт использования MVVM в реальных проектах#MBLTdev: Опыт использования MVVM в реальных проектах
#MBLTdev: Опыт использования MVVM в реальных проектахe-Legion
 
Андрей Колешко «Что не так с Rails»
Андрей Колешко «Что не так с Rails»Андрей Колешко «Что не так с Rails»
Андрей Колешко «Что не так с Rails»Olga Lavrentieva
 
SOLID and Symfony. deSymfonyDay 2014
SOLID and Symfony. deSymfonyDay 2014SOLID and Symfony. deSymfonyDay 2014
SOLID and Symfony. deSymfonyDay 2014Gonzalo Ayuso
 
diffrence between procedure oriented programming & object oriented programmin...
diffrence between procedure oriented programming & object oriented programmin...diffrence between procedure oriented programming & object oriented programmin...
diffrence between procedure oriented programming & object oriented programmin...nihar joshi
 
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.Fedor Malyshkin
 
GRASP – паттерны Объектно-Ориентированного Проектирования
GRASP – паттерны Объектно-Ориентированного ПроектированияGRASP – паттерны Объектно-Ориентированного Проектирования
GRASP – паттерны Объектно-Ориентированного ПроектированияAlexander Nemanov
 
Принципы Solid на практике
Принципы Solid на практикеПринципы Solid на практике
Принципы Solid на практикеEatDog
 
How to scale your web app
How to scale your web appHow to scale your web app
How to scale your web appGeorgio_1999
 
A Basic Django Introduction
A Basic Django IntroductionA Basic Django Introduction
A Basic Django IntroductionGanga Ram
 
Принципы объектно-ориентированного дизайна
Принципы объектно-ориентированного дизайнаПринципы объектно-ориентированного дизайна
Принципы объектно-ориентированного дизайнаСергей Шебанин
 
Введение в Python и Django
Введение в Python и DjangoВведение в Python и Django
Введение в Python и DjangoTaras Lyapun
 
Procedural vs. object oriented programming
Procedural vs. object oriented programmingProcedural vs. object oriented programming
Procedural vs. object oriented programmingHaris Bin Zahid
 
Introduction to single page application with angular js
Introduction to single page application with angular jsIntroduction to single page application with angular js
Introduction to single page application with angular jsMindfire Solutions
 

Andere mochten auch (20)

SOLID & GRASP
SOLID & GRASPSOLID & GRASP
SOLID & GRASP
 
Как писать красивый код или основы SOLID
Как писать красивый код или основы SOLIDКак писать красивый код или основы SOLID
Как писать красивый код или основы SOLID
 
Mvc, mvp and mvvm: A comparison of architectural patterns
Mvc, mvp and mvvm: A comparison of architectural patternsMvc, mvp and mvvm: A comparison of architectural patterns
Mvc, mvp and mvvm: A comparison of architectural patterns
 
Viper - чистая архитектура iOS-приложения (И. Чирков)
Viper - чистая архитектура iOS-приложения (И. Чирков)Viper - чистая архитектура iOS-приложения (И. Чирков)
Viper - чистая архитектура iOS-приложения (И. Чирков)
 
iOS-02-Паттерны ООП
iOS-02-Паттерны ООПiOS-02-Паттерны ООП
iOS-02-Паттерны ООП
 
#MBLTdev: Мобильная реклама ВКонтакте
#MBLTdev: Мобильная реклама ВКонтакте#MBLTdev: Мобильная реклама ВКонтакте
#MBLTdev: Мобильная реклама ВКонтакте
 
#MBLTdev: Опыт использования MVVM в реальных проектах
#MBLTdev: Опыт использования MVVM в реальных проектах#MBLTdev: Опыт использования MVVM в реальных проектах
#MBLTdev: Опыт использования MVVM в реальных проектах
 
Андрей Колешко «Что не так с Rails»
Андрей Колешко «Что не так с Rails»Андрей Колешко «Что не так с Rails»
Андрей Колешко «Что не так с Rails»
 
SOLID and Symfony. deSymfonyDay 2014
SOLID and Symfony. deSymfonyDay 2014SOLID and Symfony. deSymfonyDay 2014
SOLID and Symfony. deSymfonyDay 2014
 
diffrence between procedure oriented programming & object oriented programmin...
diffrence between procedure oriented programming & object oriented programmin...diffrence between procedure oriented programming & object oriented programmin...
diffrence between procedure oriented programming & object oriented programmin...
 
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
 
GRASP – паттерны Объектно-Ориентированного Проектирования
GRASP – паттерны Объектно-Ориентированного ПроектированияGRASP – паттерны Объектно-Ориентированного Проектирования
GRASP – паттерны Объектно-Ориентированного Проектирования
 
Введение в Django
Введение в DjangoВведение в Django
Введение в Django
 
Принципы Solid на практике
Принципы Solid на практикеПринципы Solid на практике
Принципы Solid на практике
 
How to scale your web app
How to scale your web appHow to scale your web app
How to scale your web app
 
A Basic Django Introduction
A Basic Django IntroductionA Basic Django Introduction
A Basic Django Introduction
 
Принципы объектно-ориентированного дизайна
Принципы объектно-ориентированного дизайнаПринципы объектно-ориентированного дизайна
Принципы объектно-ориентированного дизайна
 
Введение в Python и Django
Введение в Python и DjangoВведение в Python и Django
Введение в Python и Django
 
Procedural vs. object oriented programming
Procedural vs. object oriented programmingProcedural vs. object oriented programming
Procedural vs. object oriented programming
 
Introduction to single page application with angular js
Introduction to single page application with angular jsIntroduction to single page application with angular js
Introduction to single page application with angular js
 

Ähnlich wie Принципы проектирования S.O.L.I.D

Groovy On Grails
Groovy On GrailsGroovy On Grails
Groovy On Grailsguest32215a
 
Groovy presentation.
Groovy presentation.Groovy presentation.
Groovy presentation.Infinity
 
ZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf Conference
 
Groovy presentation on Exception #7 conference
Groovy presentation on Exception #7 conferenceGroovy presentation on Exception #7 conference
Groovy presentation on Exception #7 conferencevoituk
 
Symfony2. На чем можно сэкономить время при разработке?
Symfony2. На чем можно сэкономить время при разработке?Symfony2. На чем можно сэкономить время при разработке?
Symfony2. На чем можно сэкономить время при разработке?Stepan Tanasiychuk
 
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and DoctrineZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and DoctrineZFConf Conference
 
C# Desktop. Занятие 12.
C# Desktop. Занятие 12.C# Desktop. Занятие 12.
C# Desktop. Занятие 12.Igor Shkulipa
 
Документирование исходных текстов (javadoc)
Документирование исходных текстов (javadoc)Документирование исходных текстов (javadoc)
Документирование исходных текстов (javadoc)Fedor Malyshkin
 
паттерны программирования
паттерны программированияпаттерны программирования
паттерны программированияguestfc8ae0
 
Let’s talk about Atlas
Let’s talk about AtlasLet’s talk about Atlas
Let’s talk about AtlasArtem Sokovets
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПЧуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПKirill Chebunin
 
Techtalk#8: Design patterns in real life
Techtalk#8: Design patterns in real lifeTechtalk#8: Design patterns in real life
Techtalk#8: Design patterns in real lifeDA-14
 
Cтиль программирования
Cтиль программированияCтиль программирования
Cтиль программированияConstantin Kichinsky
 
PHP 5.4: Что нового?
PHP 5.4: Что нового?PHP 5.4: Что нового?
PHP 5.4: Что нового?phpdevby
 
Стажировка 2016-07-14 02 Евгений Тарасенко. JavaScript
Стажировка 2016-07-14 02 Евгений Тарасенко. JavaScriptСтажировка 2016-07-14 02 Евгений Тарасенко. JavaScript
Стажировка 2016-07-14 02 Евгений Тарасенко. JavaScriptSmartTools
 
Использование хранимых процедур в MySQL (Константин Осипов)
Использование хранимых процедур в MySQL (Константин Осипов)Использование хранимых процедур в MySQL (Константин Осипов)
Использование хранимых процедур в MySQL (Константин Осипов)Ontico
 
Rich UI on Dojo Toolkit and Zend Framework
Rich UI on Dojo Toolkit and Zend FrameworkRich UI on Dojo Toolkit and Zend Framework
Rich UI on Dojo Toolkit and Zend FrameworkGeorgy Turevich
 

Ähnlich wie Принципы проектирования S.O.L.I.D (20)

Groovy On Grails
Groovy On GrailsGroovy On Grails
Groovy On Grails
 
Groovy presentation.
Groovy presentation.Groovy presentation.
Groovy presentation.
 
ZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to UsZFConf 2010: What News Zend Framework 2.0 Brings to Us
ZFConf 2010: What News Zend Framework 2.0 Brings to Us
 
The Best Portlet
The Best PortletThe Best Portlet
The Best Portlet
 
Groovy presentation on Exception #7 conference
Groovy presentation on Exception #7 conferenceGroovy presentation on Exception #7 conference
Groovy presentation on Exception #7 conference
 
Refactoring
RefactoringRefactoring
Refactoring
 
Symfony2. На чем можно сэкономить время при разработке?
Symfony2. На чем можно сэкономить время при разработке?Symfony2. На чем можно сэкономить время при разработке?
Symfony2. На чем можно сэкономить время при разработке?
 
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and DoctrineZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
 
UWDC 2013, Yii2
UWDC 2013, Yii2UWDC 2013, Yii2
UWDC 2013, Yii2
 
C# Desktop. Занятие 12.
C# Desktop. Занятие 12.C# Desktop. Занятие 12.
C# Desktop. Занятие 12.
 
Документирование исходных текстов (javadoc)
Документирование исходных текстов (javadoc)Документирование исходных текстов (javadoc)
Документирование исходных текстов (javadoc)
 
паттерны программирования
паттерны программированияпаттерны программирования
паттерны программирования
 
Let’s talk about Atlas
Let’s talk about AtlasLet’s talk about Atlas
Let’s talk about Atlas
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОПЧуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОП
 
Techtalk#8: Design patterns in real life
Techtalk#8: Design patterns in real lifeTechtalk#8: Design patterns in real life
Techtalk#8: Design patterns in real life
 
Cтиль программирования
Cтиль программированияCтиль программирования
Cтиль программирования
 
PHP 5.4: Что нового?
PHP 5.4: Что нового?PHP 5.4: Что нового?
PHP 5.4: Что нового?
 
Стажировка 2016-07-14 02 Евгений Тарасенко. JavaScript
Стажировка 2016-07-14 02 Евгений Тарасенко. JavaScriptСтажировка 2016-07-14 02 Евгений Тарасенко. JavaScript
Стажировка 2016-07-14 02 Евгений Тарасенко. JavaScript
 
Использование хранимых процедур в MySQL (Константин Осипов)
Использование хранимых процедур в MySQL (Константин Осипов)Использование хранимых процедур в MySQL (Константин Осипов)
Использование хранимых процедур в MySQL (Константин Осипов)
 
Rich UI on Dojo Toolkit and Zend Framework
Rich UI on Dojo Toolkit and Zend FrameworkRich UI on Dojo Toolkit and Zend Framework
Rich UI on Dojo Toolkit and Zend Framework
 

Принципы проектирования S.O.L.I.D

  • 1. S.O.L.I.D Расшифруем: S - Single responsibility principle (SRP) O - Open/closed principle (OCP) L - Liskov substitution principle (LSP) I - Interface segregation principle (ISP) D - Dependency inversion principle (DIP)
  • 2. Зачем эти правила? Помогают построить архитектуру приложения, которое со временем возможно будет проще (дешевле) поддерживать и развивать. Помогают писать повторно используемый код.
  • 3. Принцип единственности ответственности (SRP) Не должно быть больше одной причины для изменения класса. Почему? Потому что это ведет к хрупкости дизайна (пишем один функционал - ”отваливается” другой).
  • 4. Высшая раса нарушающая SRP – это God Object Что такое ”плохо”:
  • 5. Борьба с высшей расой Лучше так:
  • 6. Принцип открытости/закрытости (OCP) Программные сущности (классы, модули, функции) должны быть открыты для расширения, но закрыты для изменения. Почему? Потому что это позволяет быстро и безболезненно реагировать на изменение бизнес-требований.
  • 7. class Logger { public function log($text) { // Сохраняем текст в лог (лог у нас будет храниться в файлах) } } class Product { private $_logger; public function __construct() { $this->_logger = new Logger(); } /* Продать товар */ public function sale() { // … продаем товар // Записываем дату продажи в лог $this->_logger->log('Sale time: '. time()); } } Чем плох этот код?
  • 8. Лог продаж в файлах?! Это же отстой! Изменение требований: лог надо хранить в БД class DBLogger { public function log($text) { // Сохраняем что-то в лог (лог у нас будет храниться в БД) } } class Product { private $_logger; public function __construct() { // Меняем класс Product, чтоб поменять логер (помните про SRP?) $this->_logger = new DBLogger(); } /* Продать товар*/ public function sale() { // Продаем товар // ... // Записываем дату продажи в лог $this->_logger->log('Sale time: '. time()); } }
  • 9. Готовимся к борьбе с изменениями требований (а не к борьбе с менеджерами) interface ILogger { public function log($text); } class Logger implements ILogger { public function log($text) { // Сохраняем что-то в лог (лог у нас будет храниться в файлах) } } class DBLogger implements ILogger { public function log($text) { // Сохраняем что-то в лог (лог у нас будет храниться в БД) } } class Product { private $_logger; public function __construct(ILogger $logger) { $this->_logger = $logger; } /* Продать товар */ public function sale() { // Продаем товар // ... // Записываем дату продажи в лог $this->_logger->log('Sale time: '. time()); } }
  • 10. Принцип подстановки Барбары Лисков (LSP) Поведение наследуемых классов не должно противоречить поведению, заданному базовым классом. Почему? Потому что клиентский код начинает считать производный класс разновидностью базового, и возможно появление кода, явно использующего этот факт.
  • 11. Байка про утку и батарейки
  • 12. Ударим кодом по уткам (базовый класс) /* Определим базовую утку */ abstract class Duck { private $_batteryStatus = 100; // Стстус заряда батареек утки (%) private $_steps = 0; // Количество шагов пройденных уткой (шт.) public function getBatteryStatus() { return $this->_batteryStatus; } public function setBatteryStatus($value) { $this->_batteryStatus = $value; } public function getSteps() { return $this->_steps; } public function setSteps($value) { $this->_steps = $value; } // Эти методы абстрактные (разные утки крякают и двигаются по-своему) abstract public function move(); abstract public function quack(); }
  • 13. Утки на батарейках (Америка, Китай) /* Американская утка на батарейках */ class AmericanDuck extends Duck { public function move() { $this->setSteps($this->getSteps() + 1); // Утка шагает $this->setBatteryStatus($this->getBatteryStatus() - 20); // Батарейки садятся echo "Я прошагала {$this->getSteps()} шагов (заряд батарейки: {$this->getBatteryStatus()}%) "; } public function quack() { echo "Здравствуйте, я Американская утка! "; } } /* Китайская утка на батарейках */ class ChinaDuck extends Duck { public function move() { $this->setSteps($this->getSteps() + 1); // Утка шагает $this->setBatteryStatus($this->getBatteryStatus() - 10); // Батарейки садятся (но не так быстро) echo "Я прошагала {$this->getSteps()} шагов (заряд батарейки: {$this->getBatteryStatus()}%) "; } public function quack() { echo "Здравствуйте, я Китайский утка, я плохо говорить по-русски, но я уметь много шагать! "; } }
  • 14. Клиентский код использования уток // Имеем список уток $duckList = array(new AmericanDuck(), new ChinaDuck()); // Просим всех уток по очереди представиться и походить foreach($duckList as $duck) { $duck->quack(); // Представимся while ($duck->getBatteryStatus() > 0) { // Утка должна шагать, пока не сядут батарейки $duck->move(); sleep(1); } echo ""; }
  • 15. Появилась возожность юзать живую утку! /* Живая утка. Её особенность в том, что у нее нет батареек и она шагает сколько хочет */ class BrainyDuck extends Duck { public function move() { $this->setSteps($this->getSteps() + 1); // Утка шагает echo "Я прошагала {$this->getSteps()} шагов "; } public function quack() { echo "Здравствуйте, я живая утка с мозгом! "; } public function getBatteryStatus() { throw new Exception('Сума сошел? Какие батарейки, я живая!'); } public function setBatteryStatus() { throw new Exception('Сума сошел? Какие батарейки, я живая!'); } }
  • 16. Клиентский код и Fail исползования уток // Имеем список уток $duckList = array(new AmericanDuck(), new ChinaDuck(), new BrainyDuck()); // Просим всех уток по очереди представиться и походить foreach($duckList as $duck) { $duck->quack(); // Представимся while ($duck->getBatteryStatus() > 0) { // Утка должна шагать, пока не сядут батарейки $duck->move(); sleep(1); } echo ""; }
  • 17. Принцип разделения интерфейса (ISP) Клиенты не должны зависеть от методов, которые они не используют. Почему? Если мы определим большой универсальный интерфейс, тогда в наследниках возможно появление множества заглушек, а соответственно, много лишнего кода, который неудобно поддерживать.
  • 18. Делаем трансформера (пока что все хорошо) interface IMegaTrsansformer { public function transformToCar(); public function transformToShip(); public function transformToPlane(); } class MegaTrsansformer implements IMegaTrsansformer { public function transformToCar() { echo 'Я преобразовался и стал спортивной машиной!'; } public function transformToShip() { echo 'Я преобразовался и стал сверхбыстрым катером!'; } public function transformToPlane() { echo 'Я преобразовался и стал истребителем!'; } }
  • 19. А теперь нужно сделать менее крутых трансформеров (в каждом из них теперь костыли) class TaxiTrsansformer implements IMegaTrsansformer { public function transformToCar() { echo 'Я преобразовался и стал такси!'; } public function transformToShip() { throw new Exception('Данная трансформация не поддерживается'); } public function transformToPlane() { throw new Exception('Данная трансформация не поддерживается'); } } class StelthTrsansformer implements IMegaTrsansformer { public function transformToCar() { throw new Exception('Данная трансформация не поддерживается'); } public function transformToShip() { throw new Exception('Данная трансформация не поддерживается'); } public function transformToPlane() { echo 'Я преобразовался и стал стелсом!'; } } class IcebreakerTrsansformer implements IMegaTrsansformer { public function transformToCar() { throw new Exception('Данная трансформация не поддерживается'); } public function transformToShip() { echo 'Я преобразовался и стал ледоколом!'; } public function transformToPlane() { throw new Exception('Данная трансформация не поддерживается'); } }
  • 20. Лучше иметь такой набор интерфейсов interface ICarTrsansformer { public function transformToCar(); } interface IShipTrsansformer { public function transformToShip(); } interface IPlaneTrsansformer { public function transformToPlane(); }
  • 21. И такой набор классов class MegaTrsansformer implements ICarTrsansformer, IShipTrsansformer, IPlaneTrsansformer { public function transformToCar() { echo 'Я преобразовался и стал спортивной машиной!'; } public function transformToShip() { echo 'Я преобразовался и стал сверхбыстрым катером!'; } public function transformToPlane() { echo 'Я преобразовался и стал истребителем!'; } } class TaxiTrsansformer implements ICarTrsansformer { public function transformToCar() { echo 'Я преобразовался и стал такси!'; } } class StelthTrsansformer implements IPlaneTrsansformer { public function transformToPlane() { echo 'Я преобразовался и стал стелсом!'; } } class IcebreakerTrsansformer implements IShipTrsansformer { public function transformToShip() { echo 'Я преобразовался и стал ледоколом!'; } }
  • 22.
  • 23. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций
  • 24. Анатомия зависимостей (X зависит от Y + циклическая зависимость) Зависимости бывают: - Прямые; - Транзитивные; - Циклические.
  • 25. Зависимость модуля верхннго уровня от модулей нижнего уровня class siteMapBilder { private $_dataStorage; private $_webGrabber; public function __construct() { $this->_dataStorage = new FileDataStorage(); $this->_webGrabber = new CurlWebGrabber(); } // ... Здесь какие-то методы для построения карты сайта }
  • 26. Освобождаем SiteMapBuilder от зависимостей (инвертируем зависимости) class siteMapBilder { private $_dataStorage; private $_webGrabber; public function __construct(WebGrabber $dataStorage, DataStorage $webGrabber) { $this->_dataStorage = $dataStorage; $this->_webGrabber = $webGrabber; } // ... Здесь какие-то методы для построения карты сайта }
  • 27. «... любые хорошо структурированные объектно-ориентированные архитектуры имеют четко определенные слои, каждый из которых поддерживает некоторый компактный набор служб с помошью хорошо определенного и контролируемого интерфейса» Г. Буч Разделение архитектуры по слоям
  • 28. Усовершенствованное разделение архитектуры по слоям Здесь мы избавились не только от транзитивной зависимости между TopLayer и DeepLayer, но и от прямых зависимостей
  • 30.
  • 31. Принцип подстановки Барбары Лисков (Василий Меленчук): http://habrahabr.ru/blogs/programming/83269/
  • 32. Принципы проектирования классов (S.O.L.I.D.) (Александр Бындю): http://blog.byndyu.ru/2009/10/solid.html
  • 33. SRP (Robert C. Martin): www.objectmentor.com/resources/articles/srp.pdf
  • 34. OCP (Robert C. Martin): http://www.objectmentor.com/resources/articles/ocp.pdf
  • 35. LSP (Robert C. Martin): http://www.objectmentor.com/resources/articles/lsp.pdf
  • 36. ISP (Robert C. Martin): http://www.objectmentor.com/resources/articles/isp.pdf
  • 37. DIP (Robert C. Martin): http://www.objectmentor.com/resources/articles/dip.pdf
  • 38. * фоновая картинка здесь используется исключительно для красоты :-)