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

Содержание

Слайд 2

Что такое SOLID

SOLID - это аббревиатура пяти основных принципов дизайна классов в

Что такое SOLID SOLID - это аббревиатура пяти основных принципов дизайна классов
объектно-ориентированном проектировании.
Аббревиатура была введена Робертом Мартином в начале 2000-х.
Рекомендую почитать:
Чистый код. Роберт Мартин

Слайд 3

Основные принципы

Single responsibility - Принцип единственной обязанности
Open-closed - Принцип открытости/закрытости
Liskov substitution -

Основные принципы Single responsibility - Принцип единственной обязанности Open-closed - Принцип открытости/закрытости
Принцип подстановки Барбары Лисков
Interface segregation - Принцип разделения интерфейса
Dependency inversion - Принцип инверсии зависимостей

Слайд 4

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

Класс или модуль должны иметь одну и только одну

Single responsibility Принцип единственной обязанности Класс или модуль должны иметь одну и только одну причину измениться.
причину измениться.

Слайд 5

Пример нарушения принципа SRP

class Order
{
public void calculate(){ ... }
public void

Пример нарушения принципа SRP class Order { public void calculate(){ ... }
addItem(Product product){ ... }
public List getItems(){ ... }
...
public void load(){ ... }
public void save(){ ... }
public void print(){ ... }
}

Слайд 6

Как исправить

class Order
{
public void calculate();
public void addItem(Product product){ ... }

Как исправить class Order { public void calculate(); public void addItem(Product product){
public List getItems(){ ... }
}
class OrderRepository
{
public Order load(int orderId){ ... }
public void save(Order order){ ... }
}
class OrderPrintManager
{
public void print(Order order){ ... }
}

Слайд 7

Но...

Существует, например, паттерн Active Record, который нарушает принцип SRP
Active Record может быть

Но... Существует, например, паттерн Active Record, который нарушает принцип SRP Active Record
успешно использован в небольших проектах с простой бизнес-логикой.

ActiveRecord post = Post.newRecord();
post.setData("title", "Happy Java Programming");
post.setData("body", "Java programming is fun.");
post.create();

Слайд 8

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

Объекты проектирования (классы, функции, модули и т.д.) должны быть открыты

Open-closed Принцип открытости/закрытости Объекты проектирования (классы, функции, модули и т.д.) должны быть
для расширения, но закрыты для модификации.
Это означает, что новое поведение должно добавляться только добавлением новых сущностей, а не изменением старых.

Слайд 9

Пример нарушения OCP

class MessageSender {

public void send(String message, MessageType type){

Пример нарушения OCP class MessageSender { … public void send(String message, MessageType
if(type == MessageType.SMS) sendSMS(msg);
else
if(type == MessageType.EMAIL) sendEmail(msg);
}
}

Слайд 10

Как исправить

Воспользуемся паттерном “Стратегия”

interface SendingStrategy {
void send(String message);
}
class MessageSender {
private

Как исправить Воспользуемся паттерном “Стратегия” interface SendingStrategy { void send(String message); }
SendingStrategy strategy;
public MessageSender(SendingStrategy strategy) {
this.strategy = strategy;
}
public void send(String message) {
this.strategy.send(message);
}
}

Слайд 11

Как исправить(продолжение)

Конкретные стратегии отправки

class EmailSendingStrategy implements SendingStrategy {
@Override
public void send(String

Как исправить(продолжение) Конкретные стратегии отправки class EmailSendingStrategy implements SendingStrategy { @Override public
message) {
System.out.println("Sending Email: " + message);
}
}
class SMSSendingStrategy implements SendingStrategy {
@Override
public void send(String message) {
System.out.println("Sending SMS: " + message);
}
}

Слайд 12

Liskov substitution Принцип подстановки Барбары Лисков

Роберт С. Мартин определил этот принцип так:

Liskov substitution Принцип подстановки Барбары Лисков Роберт С. Мартин определил этот принцип
Функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа не зная об этом.

Слайд 13

Замещение

T

S

Объекты типа T могут быть замещены объектами типа S без каких-либо изменений

Замещение T S Объекты типа T могут быть замещены объектами типа S
желательных свойств этой программы

Слайд 14

Нарушение принципа LSP

Circle-ellipse problem
Square-rectangle problem

Нарушение принципа LSP Circle-ellipse problem Square-rectangle problem

Слайд 15

Square-rectangle problem

Является ли класс Квадрат подклассом класса Прямоугольник?

Rectangle

Square

?

Square-rectangle problem Является ли класс Квадрат подклассом класса Прямоугольник? Rectangle Square ?

Слайд 16

Класс Rectangle

class Rectangle {
private double width;
private double height;
public double

Класс Rectangle class Rectangle { private double width; private double height; public
getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public String toString() {
return this.width + "x" + this.height;
}
}

Слайд 17

Класс Square

class Square extends Rectangle {
public void setWidth(double width) {
this.setSide(width);

Класс Square class Square extends Rectangle { public void setWidth(double width) {
}
public void setHeight(double height) {
this.setSide(height);
}
public void setSide(double side) {
super.setWidth(side);
super.setHeight(side);
}
}

Слайд 18

В чем же проблема?

public class LiskovViolation {
public static void main(String[] args)

В чем же проблема? public class LiskovViolation { public static void main(String[]
{
Rectangle rectangle = new Square();
rectangle.setWidth(10);
System.out.println(rectangle); // 10.0x10.0
rectangle.setHeight(20);
System.out.println(rectangle); // 20.0x20.0 !!!! Should be 10.0x20.0
}
}

Слайд 19

Как исправить

Если использовать концепцию неизменяемого объекта (immutable object), то принцип не будет

Как исправить Если использовать концепцию неизменяемого объекта (immutable object), то принцип не
нарушаться.
Необходимо убрать возможность изменения объекта после его создания.

Слайд 20

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

Слишком «толстые» интерфейсы необходимо разделять на более маленькие

Interface segregation Принцип разделения интерфейса Слишком «толстые» интерфейсы необходимо разделять на более
и специфические, чтобы клиенты маленьких интерфейсов знали только о методах, которые необходимы им в работе.

Слайд 21

“Толстый” интерфейс

Если среди методов интерфейса можно выделить группы методов, которые нужны определенным

“Толстый” интерфейс Если среди методов интерфейса можно выделить группы методов, которые нужны
пользователям интерфейса, то скорее всего интерфейс “толстый”.
Такой интерфейс нужно разбить на более мелкие, которые будут выражать потребности конкретной группы пользователей интерфейса.

Слайд 22

Пример нарушения ISP

interface Person {
void goToWork();
void withdrawSalary();
void eat();
}

Если мы

Пример нарушения ISP interface Person { void goToWork(); void withdrawSalary(); void eat();
захотим сделать реализацию, в которой единственным необходимым методом будет eat() придется реализовывать и все остальные методы

Слайд 23

Как исправить

public interface Person {
void eat();
}
public interface Worker {
void goToWork();

Как исправить public interface Person { void eat(); } public interface Worker
void withdrawSalary();
}

Слайд 24

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

Все взаимосвязи в программе должны поддерживаться с помощью

Dependency inversion Принцип инверсии зависимостей Все взаимосвязи в программе должны поддерживаться с
абстракных классом или интерфейсов.

Слайд 25

Нарушение принципа DIP

public class Crawler {
public void saveHtmlDocument() {
DomBasedHtmlParser parser

Нарушение принципа DIP public class Crawler { public void saveHtmlDocument() { DomBasedHtmlParser
= new DomBasedHtmlParser();
HtmlDocument document = parser.parseUrl("http://example.com/");
save(document, "index.html");
}
public void save(HtmlDocument htmlDocument, String pageName) {
// сохранение документа в файл
}
}

Экземпляр класса парсер создается внутри метода saveHtmlDocument() и не использует интерфейс, что делает невозможным использования другой реализации парсера и затрудняет тестирование.

Слайд 26

Как исправить. Вариант 1

public class Crawler {
private HtmlParser parser;
public Crawler(HtmlParser

Как исправить. Вариант 1 public class Crawler { private HtmlParser parser; public
parser) {
this.parser = parser;
}
public void saveHtmlDocument() {
HtmlDocument document = parser.parseUrl("http://example.com/");
save(document, "index.html");
}
public void save(HtmlDocument htmlDocument, String pageName) {
// сохранение документа в файл
}
}
Имя файла: Принципы-объективно-ориентированного-дизайна.pptx
Количество просмотров: 156
Количество скачиваний: 0