SlideShare a Scribd company logo
1 of 37
Object-Oriented
Programming
4
SOLID
д.т.н. Емельянов Виталий Александрович
: v.yemelyanov@gmail.com
Ценности качественного кода
2Емельянов В.А.: Объектно-ориентированное программирование
Расширяемость, гибкость
(extensibility, agility)
Сопровождаемость
(maintainability)
Простота
(simplicity)
Читабельность, понятность
(readability, clarity)
Тестируемость
(testability)
Принципы SOLID
 SOLID – 5 принципов объектно-ориентированного программирования,
описывающих архитектуру программного обеспечения.
 Все шаблоны проектирования (паттерны) основаны на этих принципах.
3Емельянов В.А.: Объектно-ориентированное программирование
SRP – принцип единой ответственности
Смысл SRP: на каждый объект должна быть возложена
одна единственная обязанность
4Емельянов В.А.: Объектно-ориентированное программирование
Конкретный класс должен решать только конкретную
задачу — ни больше, ни меньше.
SRP – принцип единой ответственности
5Емельянов В.А.: Объектно-ориентированное программирование
 Каждый класс имеет свои обязанности в программе
 Если у класса есть несколько обязанностей, то у него
появляется несколько причин для изменения
 Изменение одной обязанности может привести к тому, что
класс перестанет справляться с другими.
 Такого рода связанность – причина хрупкого дизайна, который
неожиданным образом разрушается при изменении
Хорошее разделение обязанностей выполняется только тогда,
когда имеется полная картина того, как приложение должно
работать.
!
SRP – принцип единой ответственности
public class Employee
{
public int ID { get; set; }
public string FullName { get; set; }
//метод Add() добавляет в БД нового сотрудника
//emp – объект (сотрудник) для вставки
public bool Add(Employee emp)
{
//код для добавления сотрудника в таблицу БД
return true;
}
// метод для создания отчета по сотруднику
public void GenerateReport(Employee em)
{
//Генерация отчета по деятельности сотрудника
}
}
C#
6Емельянов В.А.: Объектно-ориентированное программирование
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ПЛОХО: Класс Employee
не соответствует
принципу SRP
ПОЧЕМУ?
Класс несет 2 ответственности:
 добавление сотрудника в БД
 создание отчета.
Класс Employee не должен нести
ответственность за отчетность,
т.к. если вдруг надо будет
предоставить отчет в формате
Excel или изменить алгоритм
создания отчета, то потребуется
изменить класс Employee.
SRP – принцип единой ответственности
Согласно SRP, необходимо написать отдельный класс для
ответственности по генерации отчетов:
public class Employee
{
public int ID { get; set; }
public string FullName { get; set; }
public bool Add(Employee emp)
{
// Вставить данные сотрудника в таблицу БД
return true;
}
}
public class EmployeeReport
{
public void GenerateReport(Employee em)
{
// Генерация отчета по деятельности сотрудника
}
}
C#
7Емельянов В.А.: Объектно-ориентированное программирование
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
OCP – принцип открытости/закрытости
8Емельянов В.А.: Объектно-ориентированное программирование
Смысл OCP: Классы (модули) должны быть:
 открыты для расширений – модуль должен быть
разработан так, чтобы новая функциональность могла быть
добавлена только при создании новых требований.
 закрыты для модификации – означает, что мы уже
разработали класс, и он прошел модульное тестирование.
Мы не должны менять его, пока не найдем ошибки.
Расширение:Модификации внутри:
OCP – принцип открытости/закрытости
9Емельянов В.А.: Объектно-ориентированное программирование
Принцип OCP рекомендует проектировать систему так,
чтобы в будущем изменения можно было реализовать:
путем добавления нового кода,
а не изменением уже работающего кода.
КАК ЭТО ВООБЩЕ ВОЗМОЖНО?
OCP – принцип открытости/закрытости
10Емельянов В.А.: Объектно-ориентированное программирование
1. Интерфейсы фиксированы, но на их основе можно создать
неограниченное множество различных поведений:
 поведения – это производные классы от абстракций.
 они могут манипулировать абстракциями.
2. Интерфейсы (абстрактные классы):
 могут быть закрыты для модификации – являются
фиксированными;
 но их поведение можно расширять, создавая новые
производные классы.
Принцип OCP можно реализовать с помощью
интерфейсов или абстрактных классов.
OCP – принцип открытости/закрытости
public class EmployeeReport
{
//свойство - тип отчета
public string TypeReport { get; set; }
//метод для отчета по сотруднику (объект em)
public void GenerateReport(Employee em)
{
if (TypeReport == "CSV")
{
// Генерация отчета в формате CSV
}
if (TypeReport == "PDF")
{
// Генерация отчета в формате PDF
}
}
}
C#
11Емельянов В.А.: Объектно-ориентированное программирование
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ПЛОХО: Класс EmployeeReport
не соответствует
принципу OCP
ПОЧЕМУ?
Проблема в классе в том,
что если надо внести новый
тип отчета (например, для
выгрузки в Excel), тогда надо
добавить новое условие if.
Т.е. необходимо изменить
код уже работающего метода
класса EmployeeReport.
OCP – принцип открытости/закрытости
public class IEmployeeReport
{
public virtual void GenerateReport(Employee em)
{
//Базовая реализация, которую нельзя модифицировать
}
}
public class EmployeeCSVReport : IEmployeeReport
{
public override void GenerateReport(Employee em)
{
//Генерация отчета в формате CSV
}
}
public class EmployeePDFReport : IEmployeeReport
{
public override void GenerateReport(Employee em)
{
//Генерация отчета в формате PDF
}
}
C#
12Емельянов В.А.: Объектно-ориентированное программирование
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Класс IEmployeeReport закрыт от
модификаций, но доступен для
расширений.
Если надо добавить новый тип
отчета, просто надо создать
новый класс и унаследовать его
от IEmployeeReport
OCP – принцип открытости/закрытости
13Емельянов В.А.: Объектно-ориентированное программирование
Применение OCP позволяет:
 создавать системы, которые будет сохранять стабильность
при изменении требований;
 создать систему, которая будет существовать дольше
первой версии.
LSP – принцип подстановки Барбары Лисков
Смысл LSP: «вы должны иметь возможность использовать
любой производный класс вместо родительского
класса и вести себя с ним таким же образом без
внесения изменений».
14Емельянов В.А.: Объектно-ориентированное программирование
Parent Child
LSP – принцип подстановки Барбары Лисков
15Емельянов В.А.: Объектно-ориентированное программирование
Согласно LSP, классы-наследники (Manager и SalesPerson)
ведут себя также, как класс-родитель (Employee)
public abstract class Employee
{
public virtual string GetWorkDetails(int id)
{
return "Base Work";
}
public virtual string GetEmployeeDetails(int id)
{
return "Base Employee";
}
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
UML
LSP – принцип подстановки Барбары Лисков
public class Manager : Employee
{
public override string GetWorkDetails(int id)
{
return “Manager Work";
}
public override string GetEmployeeDetails(int id)
{
return “Manager Employee";
}
}
public class SalesPerson : Employee
{
public override string GetWorkDetails(int id)
{
throw new NotImplementedException();
}
public override string GetEmployeeDetails(int id)
{
return “SalesPerson Employee";
}
}
C#
16Емельянов В.А.: Объектно-ориентированное программирование
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Плохой код. ПОЧЕМУ?
UML
LSP – принцип подстановки Барбары Лисков
static void Main(string[] args)
{
List<Employee> list = new List<Employee>();
list.Add(new Manager());
list.Add(new SalesPerson());
foreach (Employee emp in list)
{
emp.GetEmployeeDetails(985);
}
}
C#
17Емельянов В.А.: Объектно-ориентированное программирование
38
39
40
41
42
43
44
45
46
47
48
49
ПРОБЛЕМА:
для SalesPerson невозможно вернуть
информацию о работе, поэтому
получаем необработанное исключение,
что нарушает принцип LSP.
LSP – принцип подстановки Барбары Лисков
Для решения этой проблемы в C# необходимо просто разбить функционал
на два интерфейса Iwork и IEmployee:
C#
18Емельянов В.А.: Объектно-ориентированное программирование
public class Manager : IWork, IEmployee
{
public string GetWorkDetails(int Id)
{
return “Manager Work";
}
public string GetEmployeeDetails(int Id)
{
return “Manager Employee";
}
}
Теперь SalesPerson требует реализации
только IEmployee, а не IWork. При таком
подходе будет поддерживаться принцип LSP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface IEmployee
{
string GetEmployeeDetails(int Id);
}
public interface IWork
{
string GetWorkDetails(int Id);
}
public class SalesPerson : IEmployee
{
public string GetEmployeeDetails(int Id)
{
return "SalesPerson Employee";
}
}
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
ISP – принцип разделения интерфейсов
19Емельянов В.А.: Объектно-ориентированное программирование
Смысл ISP: много специализированных интерфейсов лучше,
чем один универсальный
 Соблюдение этого принципа необходимо для того,
чтобы классы-клиенты использующий/реализующий
интерфейс знали только о тех методах, которые они
используют, что ведёт к уменьшению количества
неиспользуемого кода.
ISP – принцип разделения интерфейсов
Пусть есть одна база данных (БД) для хранения данных всех типов
сотрудников (типы сотрудников: Junior и Senior)
 Необходимо реализовать возможность добавления данных о
сотрудниках в БД.
 Возможный вариант интерфейса для сохранения данных по
сотрудникам:
public interface IEmployee
{
bool AddDetailsEmployee();
}
C#
20Емельянов В.А.: Объектно-ориентированное программирование
1
2
3
4
5
6
ISP – принцип разделения интерфейсов
Допустим все классы Employee наследуют интерфейс IEmployee для
сохранения данных в БД. Теперь предположим, что в компании однажды
возникла необходимость читать данные только для сотрудников в
должности Senior.
 Что делать?
 Просто добавить один метод в интерфейс?
public interface IEmployee
{
bool AddDetailsEmployee();
bool ShowDetailsEmployee(int id);
}
C#
21Емельянов В.А.: Объектно-ориентированное программирование
1
2
3
4
5
6
7
Потому что мы что-то
ломаем. Мы вынуждаем
объекты JuniorEmployee
показывать свои данные
из базы данных.
ПЛОХО: Интерфейс IEmployee
не соответствует
принципу ISP
ПОЧЕМУ?
ISP – принцип разделения интерфейсов
РЕЗУЛЬТАТ: теперь, класс JuniorEmployee будет реализовывать только
интерфейс IOperationAdd, а SeniorEmployee оба интерфейса.
Таким образом обеспечивается разделение интерфейсов.
public interface IOperationAdd
{
bool AddDetailsEmployee();
}
public interface IOperationGet
{
bool ShowDetailsEmployee(int id);
}
C#
22Емельянов В.А.: Объектно-ориентированное программирование
Согласно ISP, решение заключается в том, чтобы передать
новую ответственность другому интерфейсу:
1
2
3
4
5
6
7
8
9
DIP – принцип инверсии зависимостей
23Емельянов В.А.: Объектно-ориентированное программирование
Смысл DIP: «зависеть от абстракций, а не от деталей»
1. Модули верхних уровней не должны зависеть от модулей
нижних уровней. Модули обоих уровней должны зависеть от
абстракций.
2. Абстракции не должны зависеть от деталей. Детали
должны зависеть от абстракций.
UML
UML
DIP – принцип инверсии зависимостей
24Емельянов В.А.: Объектно-ориентированное программирование
Многослойная архитектура ПО:
 В любой хорошо структурированной объектно-ориентированной
архитектуре можно выделить ясно очерченные слои архитектуры ПО.
Пользователи
DIP – принцип инверсии зависимостей
25Емельянов В.А.: Объектно-ориентированное программирование
 Presentation Layer (уровень представления) – уровень, с которым
непосредственно взаимодействует пользователь. Этот уровень включает
компоненты пользовательского интерфейса, механизм получения ввода от
пользователя и т.д.
 Business Logic Layer (уровень бизнес-логики): содержит набор
компонентов, которые отвечают за обработку полученных от уровня
представлений данных, реализует всю необходимую логику приложения,
все вычисления, взаимодействует с базой данных и передает уровню
представления результат обработки.
 Data Access Layer (уровень доступа к данным): хранит модели,
описывающие используемые сущности, также здесь размещаются
специфичные классы для работы с разными технологиями доступа к
данным, например, класс контекста данных Entity Framework. Здесь также
хранятся репозитории, через которые уровень бизнес-логики
взаимодействует с базой данных.
DIP – принцип инверсии зависимостей
26Емельянов В.А.: Объектно-ориентированное программирование
1. Классы (модули) высокого уровня реализуют бизнес-правила или логику
в системе (приложении).
2. Низкоуровневые классы (модули) занимаются более подробными
операциями, другими словами, они могут заниматься записью
информации в базу данных или передачей сообщений в ОС и т.п.
В ЧЕМ ПРОБЛЕМА:?
ЕСЛИ высокоуровневый класс имеет зависимость от дизайна и
реализации другого класса, ВОЗНИКАЕТ РИСК ТОГО, ЧТО
ИЗМЕНЕНИЯ В ОДНОМ КЛАССЕ НАРУШАТ ДРУГОЙ КЛАСС.
РЕШЕНИЕ:
Держать высокоуровневые и низкоуровневые классы слабо
связанными. Для этого необходимо сделать их зависимыми от
абстракций, а не друг от друга.
!
DIP – принцип инверсии зависимостей
27Емельянов В.А.: Объектно-ориентированное программирование
UML
UML
DIP – принцип инверсии зависимостей
ЗАДАЧА: Требуется составить программу для расчета суммарной скидки
товара, который хранится на складе, по определенной карте
скидок.
28Емельянов В.А.: Объектно-ориентированное программирование
1. ProductService – класс с методом для расчета суммарной скидки товара
2. Класс ProductService зависит от реализации классов:
 Warehouse – склад, на котором хранится товар
 DiscountScheme – схема начисления скидки
UML
DIP – принцип инверсии зависимостей
29Емельянов В.А.: Объектно-ориентированное программирование
public class Product
{
public double Cost { get; set; }
public String Name { get; set; }
public uint Count { get; set; }
}
public class Warehouse
{
public IEnumerable<Product> GetProducts()
{
return new List<Product> { new Product {Cost=140, Name = "Tyres", Count=1000},
new Product {Cost=160, Name = "Disks", Count=200},
new Product {Cost=100, Name = "Tools", Count=100}
};
}
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
DIP – принцип инверсии зависимостей
C#
30Емельянов В.А.: Объектно-ориентированное программирование
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class DiscountScheme
{
public double GetDiscount(Product p)
{
switch(p.Name)
{
case "Tyres": return 0.01;
case "Disks": return 0.05;
case "Tools": return 0.1;
default: return 0;
}
}
}
public class ProductService
{
public double GetAllDiscount()
{
double sum = 0;
Warehouse wh = new Warehouse();
IEnumerable<Product> products = wh.GetProducts();
DiscountScheme ds = new DiscountScheme();
foreach (var p in products)
sum += p.Cost * p.Count * ds.GetDiscount(p);
return sum;
}
}
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
DIP – принцип инверсии зависимостей
31Емельянов В.А.: Объектно-ориентированное программирование
class Program
{
static void Main(string[] args)
{
ProductService ps = new ProductService();
Console.WriteLine("Discount for all products = " + ps.GetAllDiscount());
Console.ReadKey();
}
}
C#
57
58
59
60
61
62
63
64
65
66
1. По факту мы не можем без изменения ProductService рассчитать
скидку на товары, которые могут быть не только на складе Warehouse.
2. Так же нет возможности подсчитать скидку по другой карте скидок (с
другим Disctount Scheme).
ПРОБЛЕМЫ:
DIP – принцип инверсии зависимостей
32Емельянов В.А.: Объектно-ориентированное программирование
Применяем DIP:
UML
Стрелки на диаграмме классов от Warehouse и SimpleScheme
поменяли направление (инверсия зависимости). Теперь от
Warehouse и SimpleScheme (DiscountScheme) ничего не
зависит. Наоборот - они зависят от абстракций (интерфейсов).
UML
DIP – принцип инверсии зависимостей
33Емельянов В.А.: Объектно-ориентированное программирование
public interface IProductStorage
{
IEnumerable<Product> GetProducts();
}
public interface IDiscountCalculator
{
double GetDiscount(Product products);
}
public class Product
{
public double Cost { get; set; }
public String Name { get; set; }
public uint Count { get; set; }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
DIP – принцип инверсии зависимостей
34Емельянов В.А.: Объектно-ориентированное программирование
public class Warehouse : IProductStorage
{
public IEnumerable<Product> GetProducts()
{
return new List<Product> { new Product {Cost=140, Name="Tyres", Count= 1000},
new Product {Cost=160, Name="Disks", Count= 200},
new Product {Cost=100, Name="Tools", Count= 100}};
}
}
public class SimpleScheme : IDiscountCalculator
{
public double GetDiscount(Product p)
{
switch (p.Name)
{
case "Tyres": return 0.01;
case "Disks": return 0.05;
case "Tools": return 0.1;
default: return 0;
}
}
}
C#
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
DIP – принцип инверсии зависимостей
35Емельянов В.А.: Объектно-ориентированное программирование
public class ProductService
{
public double GetAllDiscount(IProductStorage storage,
IDiscountCalculator discountCalculator)
{
double sum = 0;
foreach (var p in storage.GetProducts())
sum += p.Cost * p.Count * discountCalculator.GetDiscount(p);
return sum;
}
}
class Program
{
static void Main(string[] args)
{
ProductService ps = new ProductService();
Console.WriteLine("Discount for all products = " +
ps.GetAllDiscount(new Warehouse(), new SimpleScheme()));
Console.ReadKey();
}
}
C#
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
DIP – принцип инверсии зависимостей
36Емельянов В.А.: Объектно-ориентированное программирование
Проблемы архитектуры ПО, которые устраняются с
применением DIP:
 Жесткость: изменение одного модуля ведет к изменению
других модулей
 Хрупкость: изменения приводят к неконтролируемым ошибкам
в других частях программы
 Неподвижность: модуль сложно отделить от остальной части
приложения для повторного использования
SOLID упрощенно:
37Емельянов В.А.: Объектно-ориентированное программирование
Single Responsibility
Open/Closed
Liskov Substitution
Interface Segregation
Dependency Inversion
– делай модули меньше (1 ответственность)
– делай модули расширяемыми
– наследники ведут себя так же, как родители
– дели слишком сложные интерфейсы
– используй интерфейсы

More Related Content

What's hot

我的 Windows 平台自動化經驗:基礎批次檔撰寫實務
我的 Windows 平台自動化經驗:基礎批次檔撰寫實務我的 Windows 平台自動化經驗:基礎批次檔撰寫實務
我的 Windows 平台自動化經驗:基礎批次檔撰寫實務Will Huang
 
Introduction to Khronos SYCL
Introduction to Khronos SYCLIntroduction to Khronos SYCL
Introduction to Khronos SYCLMin-Yih Hsu
 
PHP 也有 Day #35 - 精通 PHP 錯誤處理,讓除錯更自在
PHP 也有 Day #35 - 精通 PHP 錯誤處理,讓除錯更自在PHP 也有 Day #35 - 精通 PHP 錯誤處理,讓除錯更自在
PHP 也有 Day #35 - 精通 PHP 錯誤處理,讓除錯更自在Asika Simon
 
Implementing a decorator for thread synchronisation.
Implementing a decorator for thread synchronisation.Implementing a decorator for thread synchronisation.
Implementing a decorator for thread synchronisation.Graham Dumpleton
 
COSCUP 2016: Project 52 每週一個小專案來學習 Golang
COSCUP 2016: Project 52 每週一個小專案來學習 GolangCOSCUP 2016: Project 52 每週一個小專案來學習 Golang
COSCUP 2016: Project 52 每週一個小專案來學習 GolangEvan Lin
 
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用Shengyou Fan
 
Entity Framework實戰
Entity Framework實戰Entity Framework實戰
Entity Framework實戰國昭 張
 
Chapitre 1 introduction generale
Chapitre 1   introduction generaleChapitre 1   introduction generale
Chapitre 1 introduction generaleAmir Souissi
 
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率Shengyou Fan
 
Java Design Patterns Tutorial | Edureka
Java Design Patterns Tutorial | EdurekaJava Design Patterns Tutorial | Edureka
Java Design Patterns Tutorial | EdurekaEdureka!
 
Learning solid principles using c#
Learning solid principles using c#Learning solid principles using c#
Learning solid principles using c#Aditya Kumar Rajan
 

What's hot (20)

我的 Windows 平台自動化經驗:基礎批次檔撰寫實務
我的 Windows 平台自動化經驗:基礎批次檔撰寫實務我的 Windows 平台自動化經驗:基礎批次檔撰寫實務
我的 Windows 平台自動化經驗:基礎批次檔撰寫實務
 
Introduction to Khronos SYCL
Introduction to Khronos SYCLIntroduction to Khronos SYCL
Introduction to Khronos SYCL
 
Eclipse IDE
Eclipse IDEEclipse IDE
Eclipse IDE
 
Dependency Inversion Principle
Dependency Inversion PrincipleDependency Inversion Principle
Dependency Inversion Principle
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
PHP 也有 Day #35 - 精通 PHP 錯誤處理,讓除錯更自在
PHP 也有 Day #35 - 精通 PHP 錯誤處理,讓除錯更自在PHP 也有 Day #35 - 精通 PHP 錯誤處理,讓除錯更自在
PHP 也有 Day #35 - 精通 PHP 錯誤處理,讓除錯更自在
 
Implementing a decorator for thread synchronisation.
Implementing a decorator for thread synchronisation.Implementing a decorator for thread synchronisation.
Implementing a decorator for thread synchronisation.
 
O.s. lab all_experimets
O.s. lab all_experimetsO.s. lab all_experimets
O.s. lab all_experimets
 
Jcl
JclJcl
Jcl
 
COSCUP 2016: Project 52 每週一個小專案來學習 Golang
COSCUP 2016: Project 52 每週一個小專案來學習 GolangCOSCUP 2016: Project 52 每週一個小專案來學習 Golang
COSCUP 2016: Project 52 每週一個小專案來學習 Golang
 
Introduction to JavaFX
Introduction to JavaFXIntroduction to JavaFX
Introduction to JavaFX
 
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
 
Sq lite module1
Sq lite module1Sq lite module1
Sq lite module1
 
Entity Framework實戰
Entity Framework實戰Entity Framework實戰
Entity Framework實戰
 
Chapitre 1 introduction generale
Chapitre 1   introduction generaleChapitre 1   introduction generale
Chapitre 1 introduction generale
 
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
 
Java Design Patterns Tutorial | Edureka
Java Design Patterns Tutorial | EdurekaJava Design Patterns Tutorial | Edureka
Java Design Patterns Tutorial | Edureka
 
Linux Internals - Part III
Linux Internals - Part IIILinux Internals - Part III
Linux Internals - Part III
 
SPI Drivers
SPI DriversSPI Drivers
SPI Drivers
 
Learning solid principles using c#
Learning solid principles using c#Learning solid principles using c#
Learning solid principles using c#
 

Similar to Лекция 4. Принципы SOLID

Aspect Oriented Programming and Design Patterns
Aspect Oriented Programming and Design PatternsAspect Oriented Programming and Design Patterns
Aspect Oriented Programming and Design PatternsAndrey Gordienkov
 
AOP and Design Patterns (GoF)
AOP and Design Patterns (GoF)AOP and Design Patterns (GoF)
AOP and Design Patterns (GoF)Andrey Gordienkov
 
Принципы объектно-ориентированного дизайна
Принципы объектно-ориентированного дизайнаПринципы объектно-ориентированного дизайна
Принципы объектно-ориентированного дизайнаСергей Шебанин
 
DUMP-2012 - Только хардкор! - "Расширяем PHP" Сергей Горшков (index.art)
DUMP-2012 - Только хардкор! - "Расширяем PHP" Сергей Горшков (index.art) DUMP-2012 - Только хардкор! - "Расширяем PHP" Сергей Горшков (index.art)
DUMP-2012 - Только хардкор! - "Расширяем PHP" Сергей Горшков (index.art) it-people
 
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...Tatyanazaxarova
 
Асинхронное программирование в ASP.NET MVC
Асинхронное программирование в ASP.NET MVCАсинхронное программирование в ASP.NET MVC
Асинхронное программирование в ASP.NET MVCEugene Agafonov
 
Отладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программОтладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программTatyanazaxarova
 
Как перейти с двухзвенной архитектуры Desktop приложения на трехзвенную за од...
Как перейти с двухзвенной архитектуры Desktop приложения на трехзвенную за од...Как перейти с двухзвенной архитектуры Desktop приложения на трехзвенную за од...
Как перейти с двухзвенной архитектуры Desktop приложения на трехзвенную за од...GoSharp
 
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, ControllersШкола-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, ControllersГлеб Тарасов
 
Секрет производства: программный продукт, за который не будет стыдно
Секрет производства: программный продукт, за который не будет стыдноСекрет производства: программный продукт, за который не будет стыдно
Секрет производства: программный продукт, за который не будет стыдноCUSTIS
 
Андрей Кирпичев "Гибкая модульность инструментами АОП"
Андрей Кирпичев  "Гибкая модульность инструментами АОП"Андрей Кирпичев  "Гибкая модульность инструментами АОП"
Андрей Кирпичев "Гибкая модульность инструментами АОП"MskDotNet Community
 
Занимательные истории из жизни технической поддержки JVM
Занимательные истории из жизни технической поддержки JVMЗанимательные истории из жизни технической поддержки JVM
Занимательные истории из жизни технической поддержки JVMNikita Lipsky
 
Быстрее света. UA Mobile 2016.
Быстрее света. UA Mobile 2016.Быстрее света. UA Mobile 2016.
Быстрее света. UA Mobile 2016.UA Mobile
 
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
 
SOLID Principles in the real world
SOLID Principles in the real worldSOLID Principles in the real world
SOLID Principles in the real worldEPAM
 
DrupalCamp Kyiv 2011. Views - стандарт вывода списка данных. Расширение Views...
DrupalCamp Kyiv 2011. Views - стандарт вывода списка данных. Расширение Views...DrupalCamp Kyiv 2011. Views - стандарт вывода списка данных. Расширение Views...
DrupalCamp Kyiv 2011. Views - стандарт вывода списка данных. Расширение Views...Viktor Likin
 

Similar to Лекция 4. Принципы SOLID (20)

Aspect Oriented Programming and Design Patterns
Aspect Oriented Programming and Design PatternsAspect Oriented Programming and Design Patterns
Aspect Oriented Programming and Design Patterns
 
AOP and Design Patterns (GoF)
AOP and Design Patterns (GoF)AOP and Design Patterns (GoF)
AOP and Design Patterns (GoF)
 
Принципы объектно-ориентированного дизайна
Принципы объектно-ориентированного дизайнаПринципы объектно-ориентированного дизайна
Принципы объектно-ориентированного дизайна
 
DUMP-2012 - Только хардкор! - "Расширяем PHP" Сергей Горшков (index.art)
DUMP-2012 - Только хардкор! - "Расширяем PHP" Сергей Горшков (index.art) DUMP-2012 - Только хардкор! - "Расширяем PHP" Сергей Горшков (index.art)
DUMP-2012 - Только хардкор! - "Расширяем PHP" Сергей Горшков (index.art)
 
Spring in java
Spring in javaSpring in java
Spring in java
 
Refactoring
RefactoringRefactoring
Refactoring
 
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
 
Асинхронное программирование в ASP.NET MVC
Асинхронное программирование в ASP.NET MVCАсинхронное программирование в ASP.NET MVC
Асинхронное программирование в ASP.NET MVC
 
Отладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программОтладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программ
 
Как перейти с двухзвенной архитектуры Desktop приложения на трехзвенную за од...
Как перейти с двухзвенной архитектуры Desktop приложения на трехзвенную за од...Как перейти с двухзвенной архитектуры Desktop приложения на трехзвенную за од...
Как перейти с двухзвенной архитектуры Desktop приложения на трехзвенную за од...
 
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, ControllersШкола-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
 
Java 9 - Back to the Future
Java 9 - Back to the FutureJava 9 - Back to the Future
Java 9 - Back to the Future
 
Секрет производства: программный продукт, за который не будет стыдно
Секрет производства: программный продукт, за который не будет стыдноСекрет производства: программный продукт, за который не будет стыдно
Секрет производства: программный продукт, за который не будет стыдно
 
Андрей Кирпичев "Гибкая модульность инструментами АОП"
Андрей Кирпичев  "Гибкая модульность инструментами АОП"Андрей Кирпичев  "Гибкая модульность инструментами АОП"
Андрей Кирпичев "Гибкая модульность инструментами АОП"
 
Занимательные истории из жизни технической поддержки JVM
Занимательные истории из жизни технической поддержки JVMЗанимательные истории из жизни технической поддержки JVM
Занимательные истории из жизни технической поддержки JVM
 
C#5 What's new?
C#5 What's new?C#5 What's new?
C#5 What's new?
 
Быстрее света. UA Mobile 2016.
Быстрее света. UA Mobile 2016.Быстрее света. UA Mobile 2016.
Быстрее света. UA Mobile 2016.
 
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
 
SOLID Principles in the real world
SOLID Principles in the real worldSOLID Principles in the real world
SOLID Principles in the real world
 
DrupalCamp Kyiv 2011. Views - стандарт вывода списка данных. Расширение Views...
DrupalCamp Kyiv 2011. Views - стандарт вывода списка данных. Расширение Views...DrupalCamp Kyiv 2011. Views - стандарт вывода списка данных. Расширение Views...
DrupalCamp Kyiv 2011. Views - стандарт вывода списка данных. Расширение Views...
 

More from Виталий Емельянов

More from Виталий Емельянов (6)

Лекция Google Cloud Platform
Лекция Google Cloud PlatformЛекция Google Cloud Platform
Лекция Google Cloud Platform
 
Лекция 1. Архитектура информационных систем
Лекция 1. Архитектура информационных системЛекция 1. Архитектура информационных систем
Лекция 1. Архитектура информационных систем
 
Лекция 4. UML (physical model)
Лекция 4. UML (physical model)Лекция 4. UML (physical model)
Лекция 4. UML (physical model)
 
Лекция 3. UML (dynamic logical model)
Лекция 3. UML (dynamic logical model)Лекция 3. UML (dynamic logical model)
Лекция 3. UML (dynamic logical model)
 
Лекция 2. UML (static logical model)
Лекция 2. UML (static logical model)Лекция 2. UML (static logical model)
Лекция 2. UML (static logical model)
 
Лекция 3. Связи между классами
Лекция 3. Связи между классамиЛекция 3. Связи между классами
Лекция 3. Связи между классами
 

Лекция 4. Принципы SOLID

  • 1. Object-Oriented Programming 4 SOLID д.т.н. Емельянов Виталий Александрович : v.yemelyanov@gmail.com
  • 2. Ценности качественного кода 2Емельянов В.А.: Объектно-ориентированное программирование Расширяемость, гибкость (extensibility, agility) Сопровождаемость (maintainability) Простота (simplicity) Читабельность, понятность (readability, clarity) Тестируемость (testability)
  • 3. Принципы SOLID  SOLID – 5 принципов объектно-ориентированного программирования, описывающих архитектуру программного обеспечения.  Все шаблоны проектирования (паттерны) основаны на этих принципах. 3Емельянов В.А.: Объектно-ориентированное программирование
  • 4. SRP – принцип единой ответственности Смысл SRP: на каждый объект должна быть возложена одна единственная обязанность 4Емельянов В.А.: Объектно-ориентированное программирование Конкретный класс должен решать только конкретную задачу — ни больше, ни меньше.
  • 5. SRP – принцип единой ответственности 5Емельянов В.А.: Объектно-ориентированное программирование  Каждый класс имеет свои обязанности в программе  Если у класса есть несколько обязанностей, то у него появляется несколько причин для изменения  Изменение одной обязанности может привести к тому, что класс перестанет справляться с другими.  Такого рода связанность – причина хрупкого дизайна, который неожиданным образом разрушается при изменении Хорошее разделение обязанностей выполняется только тогда, когда имеется полная картина того, как приложение должно работать. !
  • 6. SRP – принцип единой ответственности public class Employee { public int ID { get; set; } public string FullName { get; set; } //метод Add() добавляет в БД нового сотрудника //emp – объект (сотрудник) для вставки public bool Add(Employee emp) { //код для добавления сотрудника в таблицу БД return true; } // метод для создания отчета по сотруднику public void GenerateReport(Employee em) { //Генерация отчета по деятельности сотрудника } } C# 6Емельянов В.А.: Объектно-ориентированное программирование 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ПЛОХО: Класс Employee не соответствует принципу SRP ПОЧЕМУ? Класс несет 2 ответственности:  добавление сотрудника в БД  создание отчета. Класс Employee не должен нести ответственность за отчетность, т.к. если вдруг надо будет предоставить отчет в формате Excel или изменить алгоритм создания отчета, то потребуется изменить класс Employee.
  • 7. SRP – принцип единой ответственности Согласно SRP, необходимо написать отдельный класс для ответственности по генерации отчетов: public class Employee { public int ID { get; set; } public string FullName { get; set; } public bool Add(Employee emp) { // Вставить данные сотрудника в таблицу БД return true; } } public class EmployeeReport { public void GenerateReport(Employee em) { // Генерация отчета по деятельности сотрудника } } C# 7Емельянов В.А.: Объектно-ориентированное программирование 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
  • 8. OCP – принцип открытости/закрытости 8Емельянов В.А.: Объектно-ориентированное программирование Смысл OCP: Классы (модули) должны быть:  открыты для расширений – модуль должен быть разработан так, чтобы новая функциональность могла быть добавлена только при создании новых требований.  закрыты для модификации – означает, что мы уже разработали класс, и он прошел модульное тестирование. Мы не должны менять его, пока не найдем ошибки. Расширение:Модификации внутри:
  • 9. OCP – принцип открытости/закрытости 9Емельянов В.А.: Объектно-ориентированное программирование Принцип OCP рекомендует проектировать систему так, чтобы в будущем изменения можно было реализовать: путем добавления нового кода, а не изменением уже работающего кода. КАК ЭТО ВООБЩЕ ВОЗМОЖНО?
  • 10. OCP – принцип открытости/закрытости 10Емельянов В.А.: Объектно-ориентированное программирование 1. Интерфейсы фиксированы, но на их основе можно создать неограниченное множество различных поведений:  поведения – это производные классы от абстракций.  они могут манипулировать абстракциями. 2. Интерфейсы (абстрактные классы):  могут быть закрыты для модификации – являются фиксированными;  но их поведение можно расширять, создавая новые производные классы. Принцип OCP можно реализовать с помощью интерфейсов или абстрактных классов.
  • 11. OCP – принцип открытости/закрытости public class EmployeeReport { //свойство - тип отчета public string TypeReport { get; set; } //метод для отчета по сотруднику (объект em) public void GenerateReport(Employee em) { if (TypeReport == "CSV") { // Генерация отчета в формате CSV } if (TypeReport == "PDF") { // Генерация отчета в формате PDF } } } C# 11Емельянов В.А.: Объектно-ориентированное программирование 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ПЛОХО: Класс EmployeeReport не соответствует принципу OCP ПОЧЕМУ? Проблема в классе в том, что если надо внести новый тип отчета (например, для выгрузки в Excel), тогда надо добавить новое условие if. Т.е. необходимо изменить код уже работающего метода класса EmployeeReport.
  • 12. OCP – принцип открытости/закрытости public class IEmployeeReport { public virtual void GenerateReport(Employee em) { //Базовая реализация, которую нельзя модифицировать } } public class EmployeeCSVReport : IEmployeeReport { public override void GenerateReport(Employee em) { //Генерация отчета в формате CSV } } public class EmployeePDFReport : IEmployeeReport { public override void GenerateReport(Employee em) { //Генерация отчета в формате PDF } } C# 12Емельянов В.А.: Объектно-ориентированное программирование 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Класс IEmployeeReport закрыт от модификаций, но доступен для расширений. Если надо добавить новый тип отчета, просто надо создать новый класс и унаследовать его от IEmployeeReport
  • 13. OCP – принцип открытости/закрытости 13Емельянов В.А.: Объектно-ориентированное программирование Применение OCP позволяет:  создавать системы, которые будет сохранять стабильность при изменении требований;  создать систему, которая будет существовать дольше первой версии.
  • 14. LSP – принцип подстановки Барбары Лисков Смысл LSP: «вы должны иметь возможность использовать любой производный класс вместо родительского класса и вести себя с ним таким же образом без внесения изменений». 14Емельянов В.А.: Объектно-ориентированное программирование Parent Child
  • 15. LSP – принцип подстановки Барбары Лисков 15Емельянов В.А.: Объектно-ориентированное программирование Согласно LSP, классы-наследники (Manager и SalesPerson) ведут себя также, как класс-родитель (Employee) public abstract class Employee { public virtual string GetWorkDetails(int id) { return "Base Work"; } public virtual string GetEmployeeDetails(int id) { return "Base Employee"; } } C# 1 2 3 4 5 6 7 8 9 10 11 12 UML
  • 16. LSP – принцип подстановки Барбары Лисков public class Manager : Employee { public override string GetWorkDetails(int id) { return “Manager Work"; } public override string GetEmployeeDetails(int id) { return “Manager Employee"; } } public class SalesPerson : Employee { public override string GetWorkDetails(int id) { throw new NotImplementedException(); } public override string GetEmployeeDetails(int id) { return “SalesPerson Employee"; } } C# 16Емельянов В.А.: Объектно-ориентированное программирование 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 Плохой код. ПОЧЕМУ? UML
  • 17. LSP – принцип подстановки Барбары Лисков static void Main(string[] args) { List<Employee> list = new List<Employee>(); list.Add(new Manager()); list.Add(new SalesPerson()); foreach (Employee emp in list) { emp.GetEmployeeDetails(985); } } C# 17Емельянов В.А.: Объектно-ориентированное программирование 38 39 40 41 42 43 44 45 46 47 48 49 ПРОБЛЕМА: для SalesPerson невозможно вернуть информацию о работе, поэтому получаем необработанное исключение, что нарушает принцип LSP.
  • 18. LSP – принцип подстановки Барбары Лисков Для решения этой проблемы в C# необходимо просто разбить функционал на два интерфейса Iwork и IEmployee: C# 18Емельянов В.А.: Объектно-ориентированное программирование public class Manager : IWork, IEmployee { public string GetWorkDetails(int Id) { return “Manager Work"; } public string GetEmployeeDetails(int Id) { return “Manager Employee"; } } Теперь SalesPerson требует реализации только IEmployee, а не IWork. При таком подходе будет поддерживаться принцип LSP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public interface IEmployee { string GetEmployeeDetails(int Id); } public interface IWork { string GetWorkDetails(int Id); } public class SalesPerson : IEmployee { public string GetEmployeeDetails(int Id) { return "SalesPerson Employee"; } } 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
  • 19. ISP – принцип разделения интерфейсов 19Емельянов В.А.: Объектно-ориентированное программирование Смысл ISP: много специализированных интерфейсов лучше, чем один универсальный  Соблюдение этого принципа необходимо для того, чтобы классы-клиенты использующий/реализующий интерфейс знали только о тех методах, которые они используют, что ведёт к уменьшению количества неиспользуемого кода.
  • 20. ISP – принцип разделения интерфейсов Пусть есть одна база данных (БД) для хранения данных всех типов сотрудников (типы сотрудников: Junior и Senior)  Необходимо реализовать возможность добавления данных о сотрудниках в БД.  Возможный вариант интерфейса для сохранения данных по сотрудникам: public interface IEmployee { bool AddDetailsEmployee(); } C# 20Емельянов В.А.: Объектно-ориентированное программирование 1 2 3 4 5 6
  • 21. ISP – принцип разделения интерфейсов Допустим все классы Employee наследуют интерфейс IEmployee для сохранения данных в БД. Теперь предположим, что в компании однажды возникла необходимость читать данные только для сотрудников в должности Senior.  Что делать?  Просто добавить один метод в интерфейс? public interface IEmployee { bool AddDetailsEmployee(); bool ShowDetailsEmployee(int id); } C# 21Емельянов В.А.: Объектно-ориентированное программирование 1 2 3 4 5 6 7 Потому что мы что-то ломаем. Мы вынуждаем объекты JuniorEmployee показывать свои данные из базы данных. ПЛОХО: Интерфейс IEmployee не соответствует принципу ISP ПОЧЕМУ?
  • 22. ISP – принцип разделения интерфейсов РЕЗУЛЬТАТ: теперь, класс JuniorEmployee будет реализовывать только интерфейс IOperationAdd, а SeniorEmployee оба интерфейса. Таким образом обеспечивается разделение интерфейсов. public interface IOperationAdd { bool AddDetailsEmployee(); } public interface IOperationGet { bool ShowDetailsEmployee(int id); } C# 22Емельянов В.А.: Объектно-ориентированное программирование Согласно ISP, решение заключается в том, чтобы передать новую ответственность другому интерфейсу: 1 2 3 4 5 6 7 8 9
  • 23. DIP – принцип инверсии зависимостей 23Емельянов В.А.: Объектно-ориентированное программирование Смысл DIP: «зависеть от абстракций, а не от деталей» 1. Модули верхних уровней не должны зависеть от модулей нижних уровней. Модули обоих уровней должны зависеть от абстракций. 2. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций. UML UML
  • 24. DIP – принцип инверсии зависимостей 24Емельянов В.А.: Объектно-ориентированное программирование Многослойная архитектура ПО:  В любой хорошо структурированной объектно-ориентированной архитектуре можно выделить ясно очерченные слои архитектуры ПО. Пользователи
  • 25. DIP – принцип инверсии зависимостей 25Емельянов В.А.: Объектно-ориентированное программирование  Presentation Layer (уровень представления) – уровень, с которым непосредственно взаимодействует пользователь. Этот уровень включает компоненты пользовательского интерфейса, механизм получения ввода от пользователя и т.д.  Business Logic Layer (уровень бизнес-логики): содержит набор компонентов, которые отвечают за обработку полученных от уровня представлений данных, реализует всю необходимую логику приложения, все вычисления, взаимодействует с базой данных и передает уровню представления результат обработки.  Data Access Layer (уровень доступа к данным): хранит модели, описывающие используемые сущности, также здесь размещаются специфичные классы для работы с разными технологиями доступа к данным, например, класс контекста данных Entity Framework. Здесь также хранятся репозитории, через которые уровень бизнес-логики взаимодействует с базой данных.
  • 26. DIP – принцип инверсии зависимостей 26Емельянов В.А.: Объектно-ориентированное программирование 1. Классы (модули) высокого уровня реализуют бизнес-правила или логику в системе (приложении). 2. Низкоуровневые классы (модули) занимаются более подробными операциями, другими словами, они могут заниматься записью информации в базу данных или передачей сообщений в ОС и т.п. В ЧЕМ ПРОБЛЕМА:? ЕСЛИ высокоуровневый класс имеет зависимость от дизайна и реализации другого класса, ВОЗНИКАЕТ РИСК ТОГО, ЧТО ИЗМЕНЕНИЯ В ОДНОМ КЛАССЕ НАРУШАТ ДРУГОЙ КЛАСС. РЕШЕНИЕ: Держать высокоуровневые и низкоуровневые классы слабо связанными. Для этого необходимо сделать их зависимыми от абстракций, а не друг от друга. !
  • 27. DIP – принцип инверсии зависимостей 27Емельянов В.А.: Объектно-ориентированное программирование UML UML
  • 28. DIP – принцип инверсии зависимостей ЗАДАЧА: Требуется составить программу для расчета суммарной скидки товара, который хранится на складе, по определенной карте скидок. 28Емельянов В.А.: Объектно-ориентированное программирование 1. ProductService – класс с методом для расчета суммарной скидки товара 2. Класс ProductService зависит от реализации классов:  Warehouse – склад, на котором хранится товар  DiscountScheme – схема начисления скидки UML
  • 29. DIP – принцип инверсии зависимостей 29Емельянов В.А.: Объектно-ориентированное программирование public class Product { public double Cost { get; set; } public String Name { get; set; } public uint Count { get; set; } } public class Warehouse { public IEnumerable<Product> GetProducts() { return new List<Product> { new Product {Cost=140, Name = "Tyres", Count=1000}, new Product {Cost=160, Name = "Disks", Count=200}, new Product {Cost=100, Name = "Tools", Count=100} }; } } C# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
  • 30. DIP – принцип инверсии зависимостей C# 30Емельянов В.А.: Объектно-ориентированное программирование 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class DiscountScheme { public double GetDiscount(Product p) { switch(p.Name) { case "Tyres": return 0.01; case "Disks": return 0.05; case "Tools": return 0.1; default: return 0; } } } public class ProductService { public double GetAllDiscount() { double sum = 0; Warehouse wh = new Warehouse(); IEnumerable<Product> products = wh.GetProducts(); DiscountScheme ds = new DiscountScheme(); foreach (var p in products) sum += p.Cost * p.Count * ds.GetDiscount(p); return sum; } } 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
  • 31. DIP – принцип инверсии зависимостей 31Емельянов В.А.: Объектно-ориентированное программирование class Program { static void Main(string[] args) { ProductService ps = new ProductService(); Console.WriteLine("Discount for all products = " + ps.GetAllDiscount()); Console.ReadKey(); } } C# 57 58 59 60 61 62 63 64 65 66 1. По факту мы не можем без изменения ProductService рассчитать скидку на товары, которые могут быть не только на складе Warehouse. 2. Так же нет возможности подсчитать скидку по другой карте скидок (с другим Disctount Scheme). ПРОБЛЕМЫ:
  • 32. DIP – принцип инверсии зависимостей 32Емельянов В.А.: Объектно-ориентированное программирование Применяем DIP: UML Стрелки на диаграмме классов от Warehouse и SimpleScheme поменяли направление (инверсия зависимости). Теперь от Warehouse и SimpleScheme (DiscountScheme) ничего не зависит. Наоборот - они зависят от абстракций (интерфейсов). UML
  • 33. DIP – принцип инверсии зависимостей 33Емельянов В.А.: Объектно-ориентированное программирование public interface IProductStorage { IEnumerable<Product> GetProducts(); } public interface IDiscountCalculator { double GetDiscount(Product products); } public class Product { public double Cost { get; set; } public String Name { get; set; } public uint Count { get; set; } } C# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
  • 34. DIP – принцип инверсии зависимостей 34Емельянов В.А.: Объектно-ориентированное программирование public class Warehouse : IProductStorage { public IEnumerable<Product> GetProducts() { return new List<Product> { new Product {Cost=140, Name="Tyres", Count= 1000}, new Product {Cost=160, Name="Disks", Count= 200}, new Product {Cost=100, Name="Tools", Count= 100}}; } } public class SimpleScheme : IDiscountCalculator { public double GetDiscount(Product p) { switch (p.Name) { case "Tyres": return 0.01; case "Disks": return 0.05; case "Tools": return 0.1; default: return 0; } } } C# 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
  • 35. DIP – принцип инверсии зависимостей 35Емельянов В.А.: Объектно-ориентированное программирование public class ProductService { public double GetAllDiscount(IProductStorage storage, IDiscountCalculator discountCalculator) { double sum = 0; foreach (var p in storage.GetProducts()) sum += p.Cost * p.Count * discountCalculator.GetDiscount(p); return sum; } } class Program { static void Main(string[] args) { ProductService ps = new ProductService(); Console.WriteLine("Discount for all products = " + ps.GetAllDiscount(new Warehouse(), new SimpleScheme())); Console.ReadKey(); } } C# 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
  • 36. DIP – принцип инверсии зависимостей 36Емельянов В.А.: Объектно-ориентированное программирование Проблемы архитектуры ПО, которые устраняются с применением DIP:  Жесткость: изменение одного модуля ведет к изменению других модулей  Хрупкость: изменения приводят к неконтролируемым ошибкам в других частях программы  Неподвижность: модуль сложно отделить от остальной части приложения для повторного использования
  • 37. SOLID упрощенно: 37Емельянов В.А.: Объектно-ориентированное программирование Single Responsibility Open/Closed Liskov Substitution Interface Segregation Dependency Inversion – делай модули меньше (1 ответственность) – делай модули расширяемыми – наследники ведут себя так же, как родители – дели слишком сложные интерфейсы – используй интерфейсы