Как избавиться от дублирования кода (2023)
Представьте, что мы разрабатываем функцию размещения заказа для разных пользователей:
- Обычный пользователь должен оплатить стоимость доставки, которая составляет 10% от стоимости товаров; скидка не предоставляется
- VIP-пользователь также должен оплатить стоимость доставки в размере 10%, но скидка будет предоставлена на 3-й товар и далее.
- Внутреннему пользователю не нужно оплачивать стоимость доставки; скидка не предоставляется.
Давайте настроим некоторые базовые объекты, над которыми мы будем работать позже, включая объект Cart и объект Item.
Теперь мы реализуем логику 3 типов корзин для покупок и будем использовать объект Map(ключ - идентификатор продавца, значение - количество товара) в качестве входного параметра. Результатом будет объект Cart.
Давайте взглянем на реализацию обычной пользовательской корзины:
В этой корзине мы получаем товары из входных данных, извлекаем необходимую информацию, включая цены доставки, цены купонов и общие цены, и устанавливаем их в объект Cart. Поскольку скидки нет, цена купона будет равна нулю.
Чем корзина VIP-пользователя будет отличаться от обычной?
Поскольку VIP пользуется скидками начиная с 3-го заказа, логика, которую необходимо изменить, - это только 2-я часть кода, которая заключается в установлении разных цен на купоны. Разделы кода 1 и 3 остаются неизменными, поскольку логика получения из входных данных и вывода общих цен остается неизменной.
Переходя к последнему типу пользователей — внутренним пользователям, скидка не предоставляется, но они не платят за доставку.
Видите ли вы дублированный код здесь?
Разделы кода 1 и 3 снова повторяются на протяжении трёх разных корзин. Если бы мы изменили логику какой-либо пользовательской корзины, нам было бы легко изменить логику и для других корзин. Это ставит под угрозу ремонтопригодность кода.
Например, если кто-то понял, что вычисление общей цены товара неверно в корзине Vip-пользователя, но он забыл, что в NormalUserCart и InternalUserCart есть одни и те же детали. Это приводит к несогласованности кода, что приведёт к ошибочной бизнес-логике.
Как же тогда мы можем улучшить код?
Мы можем использовать шаблон проектирования (шаблонный метод) шаблонов для реализации общего шаблона в родительском классе.
Как мы можем увидеть из кода, раздел кода 2 заменён здесь двумя абстрактными методами processCouponPrice и processDeliveryPrice.
Теперь мы снова готовы внедрять NormalUserCart (обычную пользовательскую корзину):
Аналогично, у нас может быть VipUserCart и InternalUserCart:
Вы также заметили, что мы даём имя Spring bean в аннотации “Service”. Поскольку все три класса являются XXXUserCart, мы можем использовать String для получения имени корзины покупок и использовать Spring IoC для получения AbstractCart. Благодаря этому мы внедрили шаблон заводского проектирования:
Теперь, если у нас появится новый тип пользователя, скажем, “Корпоративный” пользователь, и для него будет создано новое правило скидки, нам не нужно будет делать ничего для текущего кода. Нам нужно только создать CorporateUserCart, чтобы расширить AbstractCart для реализовать логику.
Благодаря этому мы можем расшифровать букву “О” в ТВЁРДОМ принципе:
Открыт для расширения, закрыт для модификации.
Я надеюсь, что данная статья будет полезна для вас!
Статья была взята со следующего источника: