Лабораторная работа № XI : Шаблоны проектирования в объектно- ориентированных системах.

(проект лабораторной работы и будет правиться по результатам лаб 10)

Лабораторная работа № 11 — «Шаблоны проектирования и SOLID на существующем коде»

Перед началом сгенерируйте в ИИ намеренно плохой код:


public BigDecimal calculateFee(
        Transaction t,
        String strategy
) {
    if ("STANDARD".equals(strategy)) {
        ...
    } else if ("PREMIUM".equals(strategy)) {
        ...
    } else if ("STUDENT".equals(strategy)) {
        ...
    }

    ...
}


и:


if (format.equals("CSV")) { ... }
else if (format.equals("JSON")) { ... }
else if (format.equals("TEXT")) { ... }


Затем последовательно решаются четыре задачи.

Strategy.


public interface FeeStrategy {
    BigDecimal calculate(Transaction transaction);
}


Реализации:


StandardFeeStrategy
StudentFeeStrategy
PremiumFeeStrategy


Клиент:


public class FeeService {

    private final FeeStrategy strategy;

    public FeeService(FeeStrategy strategy) {
        this.strategy = strategy;
    }
}


Главный вопрос: почему это лучше цепочки if/switch, если алгоритмы действительно взаимозаменяемы?

Observer.

Студент создаёт собственную простую модель:


public interface TransactionListener {
    void onTransactionCreated(Transaction transaction);
}


Наблюдатели:


AuditListener
LargeExpenseAlertListener
StatisticsListener


После добавления операции сервис публикует событие, не зная деталей реакции.

Не стоит строить лабораторную на старом java.util.Observable: студенту полезнее реализовать контракт самостоятельно, а затем на защите связать идею с event-механизмами framework'ов.

Factory Method.

Здесь важно не называть любой switch, возвращающий объект, «Factory Method». Лучше показать собственно идею overridable creation method:


public abstract class ReportGenerator {

    public final String generate(
            List<Transaction> transactions
    ) {
        ReportFormatter formatter = createFormatter();
        return formatter.format(transactions);
    }

    protected abstract ReportFormatter createFormatter();
}



public class CsvReportGenerator
        extends ReportGenerator {

    @Override
    protected ReportFormatter createFormatter() {
        return new CsvReportFormatter();
    }
}


Студент сравнивает это с простой статической фабрикой и объясняет различие.

Singleton.

Singleton не следует превращать в обязательную архитектуру приложения. Практическая задача состоит из двух шагов: студент реализует небольшой корректный singleton, например через enum, а затем анализирует, что произойдёт, если сделать singleton'ом TransactionService с глобальным mutable state.

После Spring-лабораторной появляется хороший контрольный вопрос:

Одинаковы ли GoF Singleton и Spring bean с singleton scope?

Ответ: нет. У них родственная идея «один экземпляр в некоторой области», но Spring управляет lifecycle и scope внутри контейнера, а GoF Singleton кодирует контроль экземпляра самим классом. Spring действительно использует singleton как default bean scope, но это scope контейнера, а не требование добавлять private static instance в каждый сервис.

SOLID-анализ.

Студенту не требуется заучивать SOLID отдельно от кода. Он заполняет таблицу:

Изменение Какой принцип затронут
Убрали печать из Transaction SRP
Сервис зависит от TransactionRepository, а не JPA-класса DIP
Новый fee algorithm добавляется новым Strategy OCP
Маленькие специализированные interfaces ISP
Реализации repository взаимозаменяемы LSP/DIP

Для каждого паттерна студент отвечает на три вопроса:

какая проблема была до паттерна?
какие участники появились?
какую цену/сложность добавил паттерн?

Это защищает курс от классической ошибки «паттерны всегда улучшают код». Паттерн должен появляться из проблемы.


Вопросы для углубления: 
Что такое паттерн проектирования и чем он
отличается от «архитектурного стиля»?Какие есть
группы паттернов
(порождающие/структурные/поведенческие)?В
каких ситуациях уместны Singleton и Factory
Method?В чем идея Observer и Strategy (задачи,
которые они решают)?Как связаны принципы
SOLID и применение паттернов?
Автор: к.п.н., Румянцев Сергей Александрович, доцент Финансового университета при Правительстве РФ; доцент ОЧУВО Международного инновационного университета; Консалтинг, управление разработкой ПО; системный и бизнес анализ; менеджмент; аналитиз данных; управление ИТ. Телефон для связи +79269444818 (мессенджеры)   Короткая ссылка:
(проект лабораторной работы и будет правиться по результатам лаб 10)

Лабораторная работа № 11 — «Шаблоны проектирования и SOLID на существующем коде»

Перед началом сгенерируйте в ИИ намеренно плохой код:


public BigDecimal calculateFee(
        Transaction t,
        String strategy
) {
    if ("STANDARD".equals(strategy)) {
        ...
    } else if ("PREMIUM".equals(strategy)) {
        ...
    } else if ("STUDENT".equals(strategy)) {
        ...
    }

    ...
}


и:


if (format.equals("CSV")) { ... }
else if (format.equals("JSON")) { ... }
else if (format.equals("TEXT")) { ... }


Затем последовательно решаются четыре задачи.

Strategy.


public interface FeeStrategy {
    BigDecimal calculate(Transaction transaction);
}


Реализации:


StandardFeeStrategy
StudentFeeStrategy
PremiumFeeStrategy


Клиент:


public class FeeService {

    private final FeeStrategy strategy;

    public FeeService(FeeStrategy strategy) {
        this.strategy = strategy;
    }
}


Главный вопрос: почему это лучше цепочки if/switch, если алгоритмы действительно взаимозаменяемы?

Observer.

Студент создаёт собственную простую модель:


public interface TransactionListener {
    void onTransactionCreated(Transaction transaction);
}


Наблюдатели:


AuditListener
LargeExpenseAlertListener
StatisticsListener


После добавления операции сервис публикует событие, не зная деталей реакции.

Не стоит строить лабораторную на старом java.util.Observable: студенту полезнее реализовать контракт самостоятельно, а затем на защите связать идею с event-механизмами framework'ов.

Factory Method.

Здесь важно не называть любой switch, возвращающий объект, «Factory Method». Лучше показать собственно идею overridable creation method:


public abstract class ReportGenerator {

    public final String generate(
            List<Transaction> transactions
    ) {
        ReportFormatter formatter = createFormatter();
        return formatter.format(transactions);
    }

    protected abstract ReportFormatter createFormatter();
}



public class CsvReportGenerator
        extends ReportGenerator {

    @Override
    protected ReportFormatter createFormatter() {
        return new CsvReportFormatter();
    }
}


Студент сравнивает это с простой статической фабрикой и объясняет различие.

Singleton.

Singleton не следует превращать в обязательную архитектуру приложения. Практическая задача состоит из двух шагов: студент реализует небольшой корректный singleton, например через enum, а затем анализирует, что произойдёт, если сделать singleton'ом TransactionService с глобальным mutable state.

После Spring-лабораторной появляется хороший контрольный вопрос:

Одинаковы ли GoF Singleton и Spring bean с singleton scope?

Ответ: нет. У них родственная идея «один экземпляр в некоторой области», но Spring управляет lifecycle и scope внутри контейнера, а GoF Singleton кодирует контроль экземпляра самим классом. Spring действительно использует singleton как default bean scope, но это scope контейнера, а не требование добавлять private static instance в каждый сервис.

SOLID-анализ.

Студенту не требуется заучивать SOLID отдельно от кода. Он заполняет таблицу:

Изменение Какой принцип затронут
Убрали печать из Transaction SRP
Сервис зависит от TransactionRepository, а не JPA-класса DIP
Новый fee algorithm добавляется новым Strategy OCP
Маленькие специализированные interfaces ISP
Реализации repository взаимозаменяемы LSP/DIP

Для каждого паттерна студент отвечает на три вопроса:

какая проблема была до паттерна?
какие участники появились?
какую цену/сложность добавил паттерн?

Это защищает курс от классической ошибки «паттерны всегда улучшают код». Паттерн должен появляться из проблемы.


Вопросы для углубления: 
Что такое паттерн проектирования и чем он
отличается от «архитектурного стиля»?Какие есть
группы паттернов
(порождающие/структурные/поведенческие)?В
каких ситуациях уместны Singleton и Factory
Method?В чем идея Observer и Strategy (задачи,
которые они решают)?Как связаны принципы
SOLID и применение паттернов?
https://webprogr.ru/~Z2TDj
Короткая ссылка на новость:https://webprogr.ru/~Z2TDj


Последние новости

Лабораторная работа № XI : Шаблоны проектирования в объектно- ориентированных системах.

(проект лабораторной работы и будет правиться по результатам лаб 10)

Лабораторная работа № 11 — «Шаблоны проектирования и SOLID на существующем коде»

Перед началом сгенерируйте в ИИ намеренно плохой код:


public BigDecimal calculateFee(
        Transaction t,
        String strategy
) {
    if ("STANDARD".equals(strategy)) {
        ...
    } else if ("PREMIUM".equals(strategy)) {
        ...
    } else if ("STUDENT".equals(strategy)) {
        ...
    }

    ...
}


и:


if (format.equals("CSV")) { ... }
else if (format.equals("JSON")) { ... }
else if (format.equals("TEXT")) { ... }


Затем последовательно решаются четыре задачи.

Strategy.


public interface FeeStrategy {
    BigDecimal calculate(Transaction transaction);
}


Реализации:


StandardFeeStrategy
StudentFeeStrategy
PremiumFeeStrategy


Клиент:


public class FeeService {

    private final FeeStrategy strategy;

    public FeeService(FeeStrategy strategy) {
        this.strategy = strategy;
    }
}


Главный вопрос: почему это лучше цепочки if/switch, если алгоритмы действительно взаимозаменяемы?

Observer.

Студент создаёт собственную простую модель:


public interface TransactionListener {
    void onTransactionCreated(Transaction transaction);
}


Наблюдатели:


AuditListener
LargeExpenseAlertListener
StatisticsListener


После добавления операции сервис публикует событие, не зная деталей реакции.

Не стоит строить лабораторную на старом java.util.Observable: студенту полезнее реализовать контракт самостоятельно, а затем на защите связать идею с event-механизмами framework'ов.

Factory Method.

Здесь важно не называть любой switch, возвращающий объект, «Factory Method». Лучше показать собственно идею overridable creation method:


public abstract class ReportGenerator {

    public final String generate(
            List<Transaction> transactions
    ) {
        ReportFormatter formatter = createFormatter();
        return formatter.format(transactions);
    }

    protected abstract ReportFormatter createFormatter();
}



public class CsvReportGenerator
        extends ReportGenerator {

    @Override
    protected ReportFormatter createFormatter() {
        return new CsvReportFormatter();
    }
}


Студент сравнивает это с простой статической фабрикой и объясняет различие.

Singleton.

Singleton не следует превращать в обязательную архитектуру приложения. Практическая задача состоит из двух шагов: студент реализует небольшой корректный singleton, например через enum, а затем анализирует, что произойдёт, если сделать singleton'ом TransactionService с глобальным mutable state.

После Spring-лабораторной появляется хороший контрольный вопрос:

Одинаковы ли GoF Singleton и Spring bean с singleton scope?

Ответ: нет. У них родственная идея «один экземпляр в некоторой области», но Spring управляет lifecycle и scope внутри контейнера, а GoF Singleton кодирует контроль экземпляра самим классом. Spring действительно использует singleton как default bean scope, но это scope контейнера, а не требование добавлять private static instance в каждый сервис.

SOLID-анализ.

Студенту не требуется заучивать SOLID отдельно от кода. Он заполняет таблицу:

Изменение Какой принцип затронут
Убрали печать из Transaction SRP
Сервис зависит от TransactionRepository, а не JPA-класса DIP
Новый fee algorithm добавляется новым Strategy OCP
Маленькие специализированные interfaces ISP
Реализации repository взаимозаменяемы LSP/DIP

Для каждого паттерна студент отвечает на три вопроса:

какая проблема была до паттерна?
какие участники появились?
какую цену/сложность добавил паттерн?

Это защищает курс от классической ошибки «паттерны всегда улучшают код». Паттерн должен появляться из проблемы.


Вопросы для углубления: 
Что такое паттерн проектирования и чем он
отличается от «архитектурного стиля»?Какие есть
группы паттернов
(порождающие/структурные/поведенческие)?В
каких ситуациях уместны Singleton и Factory
Method?В чем идея Observer и Strategy (задачи,
которые они решают)?Как связаны принципы
SOLID и применение паттернов?
Рейтинг@Mail.ru