Привет, Хабр.
Меня зовут Владислав Родин.
В настоящее время я являюсь руководителем курса High Workload Architect в OTUS, а также преподаю курсы по архитектуре программного обеспечения.
Специально к началу набора на новый курс «Архитектура и шаблоны проектирования».
Я написал небольшой материал, которым рад с вами поделиться.
Введение
Описанные в книге Крейга Лармана «Применение UML и шаблонов, 3-е издание», шаблоны GRASP являются обобщением шаблонов GoF, а также прямым следствием принципов ООП.Они дополняют недостающую ступеньку логической лестницы, которая позволяет выводить шаблоны GoF из принципов ООП.
Шаблоны GRASP — это не шаблоны проектирования (например, GoF), а фундаментальные принципы распределения обязанностей между классами.
Как показывает практика, они не пользуются особой популярностью, но анализ спроектированных классов с использованием полного набора паттернов GRASP — необходимое условие написания хорошего кода.
Полный список шаблонов GRASP состоит из 9 элементов: Информационный эксперт Создатель Контроллер Низкая связь Высокая сплоченность Полиморфизм Чистое производство Косвенность Защищенные варианты В прошлый раз мы обсуждали принцип Информационный эксперт .
Теперь предлагаю рассмотреть Creator, аналогичный ему.
Создатель
Формулировка
Этот шаблон решает ту же типичную проблему, что и его предшественник: класс, которому они нужны, должен создать экземпляры класса .
Пример нарушения
Рассмотрим ту же проблему с заказами и товарами.Предположим, что написанный нами код соответствует Information Expert:
Несмотря, опять же, на кажущуюся тривиальность изучаемого нами принципа, в некотором клиентском коде можно будет найти следующее:@Setter @Getter @AllArgsConstructor public class Order { private List<OrderItem> orderItems; private String destinationAddress; public int getPrice() { int result = 0; for(OrderItem orderItem : orderItems) { result += orderItem.getPrice(); } return result; } } @Setter @Getter @AllArgsConstructor public class OrderItem { private Good good; private int amount; public int getPrice() { return amount * good.getPrice(); } } @Setter @Getter @AllArgsConstructor public class Good { private String name; private int price; }
public class Client {
public void doSmth() {
Good good = new Good("name", 2);
OrderItem orderItem = new OrderItem(good, amount);
List<OrderItem> orderItems = new ArrayList<>();
orderItems.add(orderItem);
Order order = new Order(orderItems, "abc");
// client code
}
}
Если вы построите диаграмму классов UML, вы обнаружите, что класс Client теперь зависит от класса Order и всех его внутренних компонентов: OrderItem и Good. Таким образом, мы не можем повторно использовать класс Client без вышеуказанных классов, которые Клиенту не нужны.
Мы фактически свели на нет все усилия по соблюдению требований Information Expert, поскольку все объекты были созданы классом Client. В устаревших проектах часто можно увидеть, как один класс создает объект другого и передает его в качестве параметра в методе через 5-6 классов, внутри которых этот объект не используется.
Это не что иное, как добавление нескольких зависимостей с нуля.
Пример приложения
Исправим распределение обязанностей между классами, чтобы распределение устраивало не только Эксперта по Информации, но и Создателя: @Setter
@Getter
public class Order {
private List<OrderItem> orderItems = new ArrayList<>();
private String destinationAddress;
public Order(String destinationAddress) {
this.destinationAddress = destinationAddress;
}
public int getPrice() {
int result = 0;
for(OrderItem orderItem : orderItems) {
result += orderItem.getPrice();
}
return result;
}
public void addOrderItem(int amount, String name, int price) {
orderItems.add(new OrderItem(amount, name, price));
}
}
@Setter
@Getter
public class OrderItem {
private Good good;
private int amount;
public OrderItem(int amount, String name, int price) {
this.amount = amount;
this.good = new Good(name, price);
}
public int getPrice() {
return amount * good.getPrice();
}
}
@Setter
@Getter
@AllArgsConstructor
public class Good {
private String name;
private int price;
}
Теперь количество зависимостей между классами будет минимальным.
Клиентский код несколько упрощен и может выглядеть так: public class Client {
public void doSmth() {
Order order = new Order("address");
order.addOrderItem(amount, name, price);
// client code
}
}
Заключение
Creator, о котором разработчики часто забывают, можно считать частным случаем Information Expert, поскольку вызов конструктора — это то же самое, что вызов метода.Соблюдение его совместно с Information Expert позволяет добиться минимального количества связей между классами и большей возможности повторного использования.
Теги: #программирование #архитектура #Анализ и проектирование систем #ООП #Промышленное программирование #проектирование #проектирование и рефакторинг #паттерны #рефакторинг #solid #полиморфизм #паттерны #хватка #инкапсуляция #наследование #информация #эксперт #craig #larman #gof # дублирование #создатель #создатель
-
Yota – Или Как Можно Всё Узнать
19 Oct, 24 -
Mars Express Будет Работать До 2018 Года.
19 Oct, 24 -
Аспия 0.2.5
19 Oct, 24 -
Chaos Constructions 2010: Выставка
19 Oct, 24