28.09K

SOLID

1.

Принципы проектирования
Создание гибких и расширяемых программ
Упрощение тестирования и поддержки
Носят *рекомендательный характер

2.

SOLID
S — Single Responsibility Principle
O — Open/Closed Principle
L — Liskov Substitution Principle
I — Interface Segregation Principle
D — Dependency Inversion Principle

3.

Single Responsibility Principle
Принцип единственной ответственности
Каждый отдельный класс должен
специализироваться только на решении
одной узкой задачи

4.

До
class Order {
public void calculateTotalSum() { }
public void getItems() { }
public void addItem(Item item) { }
public void printOrder() { }
}

5.

До
class Order {
public void calculateTotalSum() { }
public void getItems() { }
public void addItem(Item item) { }
public void printOrder() { } // Куда? Как?
}

6.

Проблема
Класс ответственен и за хранение данных, и
за их внешнюю обработку
При желании изменить способ печати
придется менять класс Order

7.

После
class Order {
public void calculateTotalSum() { }
public void getItems() { }
public void addItem(Item item) { }
}
// Каждый класс ответственен только за ограниченный набор задач
class OrderPrinter {
public void printOrder(Order order) { }
}

8.

The Open/Closed Principle
Принцип открытости/закрытости
Программные сущности должны быть
открыты для расширения, но закрыты для
модификации.

9.

До
class AreaCalculator {
public double calculateArea(Object shape) {
if (shape instanceof Rectangle) {
// some calculations
}
else if (shape instanceof Circle) {
// some calculations
}

10.

До
class AreaCalculator {
public double calculateArea(Object shape) {
if (shape instanceof Rectangle) {
// some calculations
}
else if (shape instanceof Circle) {
// some calculations
}

11.

Проблема
При добавлении новых сущностей придется
изменять уже написанный код

12.

После
interface Shape {
double calculateArea();
} // Закрытая для модификации абстракция
class Rectangle implements Shape {
@Override
public double calculateArea() { }
} // Конкретные расширяемые реализации
class Circle implements Shape {
@Override
public double calculateArea() { }
} // Конкретные расширяемые реализации

13.

The Liskov Substitution Principle
Принцип подстановки Барбары Лисков
Объекты в программе должны быть
заменяемыми на экземпляры их подтипов
без изменения правильности выполнения
программы.

14.

До
class Rectangle {
protected int width;
protected int height;
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public int getArea() {
class Square extends Rectangle {
@Override
public void setWidth(int width) {
super.setWidth(width);
super.setHeight(width);
}
@Override
public void setHeight(int height)
{
super.setHeight(height);

15.

До
class Rectangle {
protected int width;
protected int height;
class Square extends Rectangle {
@Override
public void setWidth(int width) {
super.setWidth(width);
super.setHeight(width);
} // Меняется логика родителя
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
@Override
this.height = height;
public void setHeight(int height)
}
{
public int getArea() {
super.setHeight(height);

16.

public class Test {
public static void main(String[ ] args) {
Rectangle rectangle = new Square();
rectangle.setWidth(5);
rectangle.setHeight(10);
System.out.println(rectangle.getArea());
} // Ожидаем площадь 50, но по факту 100
}

17.

После
interface Shape {
int getArea();
}
class Rectangle implements Shape {
// some methods
}
class Square implements Shape {
// some methods
}

18.

The Interface Segregation Principle
Принцип разделения интерфейса
Много специализированных интерфейсов
лучше, чем один универсальный
Клиенты не должны зависеть от методов,
которые они не используют.

19.

До
interface Unit {
void heal();
void defend();
void attack();
}
class Healer implements Unit {
public void heal() { }
public void defend() {
throw new UnsupportedActionException("healers have no
protection!");

20.

До
interface Unit {
void heal();
void defend();
void attack();
} // Интерфейс, который отвечает за все возможные действия
юнитов
class Healer implements Unit {
public void heal() { }
public void defend() {
throw new UnsupportedActionException("healers have no

21.

Проблема
«Толстый» интерфейс
Классы отвечают за те методы, которые не
используют

22.

После
// Несколько небольших специфичных интерфейсов
interface Healing {
void heal();
class Knight implements Defendable, Fightable {
}
void fight();
void defend();
interface Defendable {
}
void defend();
}
interface Fightable {
void fight();
}
class Healer implements Healing {

23.

The Dependency Inversion Principle
Модули верхнего уровня не должны зависеть
от модулей нижнего уровня. И те, и другие
должны зависеть от абстракций
Абстракции не должны зависеть от деталей.
Детали должны зависеть от абстракций

24.

class GamingMouse {
void click();
}
До
class Computer {
private GamingMouse mouse;
public Computer() {
this.mouse = new GamingMouse();
}
public void work() {

25.

До
class GamingMouse {
void click();
} // Реализация конкретной мышки
class Computer {
private GamingMouse mouse; // А если захотим использовать
другую мышь? Имеется прямая зависимость
public Computer() {
this.mouse = new GamingMouse(); // Привязаны к конкретной
сущности
}

26.

Проблема
Если понадобится использовать другие
детали, то придется переделывать класс,
зависящий от этих деталей

27.

После
interface Mouse {
void click();
}
class GamingMouse implements Mouse {
void click(){ };
} // Конкретные устройства реализуют интерфейс
class WirelessMouse implements Mouse {
void click(){ };
} // Конкретные устройства реализуют интерфейс

28.

После
class Computer {
private Mouse mouse; // зависимость от интерфейса, а не от
деталей
public Computer(Mouse mouse){
this.mouse = mouse;
}
public void work() {
mouse.click();
}
English     Русский Rules