«On Dao Architect» элегантно решает новые требования в историческом коде

Java Архитектура Шаблоны проектирования
«On Dao Architect» элегантно решает новые требования в историческом коде

⚠️Эта статья является первой подписанной статьей сообщества Nuggets, и её перепечатка без разрешения запрещена.


причина события

В середине июня прекрасный продукт дал мне временный спрос, требуя от меня商品创建/更新业务中由开放平台对接而来的请求做一个Check,如果符合要求,则再做一段稍微复杂的逻辑处理.

этоEasyКак требование уровня могло меня остановить?Менее чем за полдня я закончил Coding and Pushing одним махом.Как раз, когда я собирался заказать чашку HEYTEA и начать рыбалку, я получил электронное письмо.

В письме много китайских и английских иероглифов, но несколько слов выделяются:

您的代码已被驳回。

Когда я прошел через эмоциональные изменения, ошеломленные, шокированные, невероятные и, наконец, отказывающиеся принимать, я спросил своего коллегу по обзору, почему мой код был отклонен, и он сказал: "Общий бизнес исторического кода очень полный (так же, как Шишан...), поэтому, если есть новые требования, которые должны полагаться на него, как можно?

Делать — лучшее решение, чтобы код имел лучшую масштабируемость, вы когда-нибудь задумывались об этом?".

Я определенно не думал об этом, поэтому с небольшим чувством вины я нашел архитектора, надеясь, что он сможет дать мне какой-нибудь совет.


Найдите место, которое выглядит подходящим, чтобы поместить его.

яркая архитектура: Кервин, этот код ленивый?

try {
   // 忽略历史业务代码,以下为新增内容         
} catch (Exception) {
   // TODO
} finally {
    SkuMainBean retVal = skuMainBridgeService.updateSkuBridgeMainBean(skuMainBean);
    if(retVal != null){
        // 商品创建/修改异步处理逻辑
        SimpleThreadPool.executeRunnable(SimpleThreadPool.ThreadPoolName.openSkuHandle, () -> {
            skuOperateBusinessService.checkOpenSkuReview(retVal);
        });
    }
}

Я (хоть я и не считаю это правильным, но все равно притворяюсь спокойным): я не ленивый, вы можете видеть, что этот кусок бизнес-кода не влияет на исходную функцию, и использует пул потоков для асинхронной обработки, что не повлияет на общую эффективность интерфейса, а также инкапсулирует сложную логику вBusinessСлой, это еще называется ленью?

яркая архитектура: Считаете ли вы этот процесс создания/модификации продукта важным? Это наш основной процесс? Следующий продукт выдвинет новые требования,继续 if 然后叠罗汉吗? Насколько я помню, ты говорил, что больше всего ненавидишь видеть в коде?ifШерстяная ткань?

я (тихо): Я ненавижу видеть чужие "если", но мое собственное приемлемо...

Яркая архитектура (газовый смех): Не будем с вами тупить, давайте вместе подумаем, как его поменять.

PS: [Найдите подходящее место для его размещения] Этот метод мы используем чаще всего, он оказывает относительно небольшое влияние и имеет самую высокую эффективность разработки, но проблема, которую он приносит, заключается в том, что его нелегко поддерживать позже. , а по мере увеличения спроса станет таким же, как стекирование Архатов.Изначально очень простой метод function станет "горой дерьма" с сотнями строк, поэтому его нужно использовать по назначению.


Прекращение приоритетной проверки

Я (начинает думать): Если требуется прекратить выполнение при невыполнении определенного условия, то эта ситуация слишком проста, поэтому я не буду о ней говорить.

яркая архитектура: На самом деле есть еще что сказать, типа你需要在不满足时返回标识符结果加细节原因,你怎么处理?

я: определить строку напрямую и вернуть ее, а затем определить, является ли строка NULL.

яркая архитектура: Что, если это просто не удалось, и причина также NULL или пустая строка? На самом деле мы используем泛型Есть более элегантные решения, например определение кортежа следующим образом:

public class ValueMsgReturn<A, B> {
    /** 结果 **/
    private final A value;

    /** 原因 **/
    private final B msg;

    public ValueMsgReturn(A value, B msg) {
        this.value = value;
        this.msg = msg;
    }

    // 省略Get方法
}

Преимущество этого в том, что он общий и простой, и вам не нужно определять повторяющиеся объекты. Вы можете увидеть, насколько это ароматно, попробовав его в коде. Общий код выглядит следующим образом:

// 省略干扰代码
ValueMsgReturn<Boolean, String> check = check();
if (check.getValue()) {
    return check.getValue();
}

PS: Ситуация относительно простая, но навыки по оптимизации кода все же есть, подробнее в исторической статье:

Как написать минимальный код


Простой шаблон наблюдателя

Я (продолжаю думать): Ваша ситуация слишком проста, вернемся к теме, мы можем использовать это требование观察者模式解耦Какие!

Яркая архитектура (колеблясь): Это не невозможно, но подумайте, какой код нам нужно изменить.

я: Ядром наблюдателя является通知方 + 处理方, если мы используем режим наблюдателя, поставляемый с JDK, изменения следующие:

  1. Нужно наследовать класс в историческом кодеObservableсвоего рода
  2. Новый метод обработки абстрагируется в отдельный класс по единому принципу, который реализуетObserverинтерфейс
  3. Создайте отношение уведомления между ними при инициализации класса.

яркая архитектура: Если часть логики разработана с помощью шаблона наблюдателя, это нормально, но исторический код не подходит,因为它一个类里面包含大量的其他方法, если возникнет вторая ситуация, о которой нужно уведомить в будущем, код будет сложнее поддерживать, ведь режим наблюдателя JDK нужно наследоватьObservableКласс, конечно, невозможен как альтернатива.

PS: Описанный выше режим наблюдателя JDK соответствует версии JDK 1.8.Подробнее о режиме наблюдателя см. в исторической статье

[Серия «Учимся вместе»] Режим наблюдателя: я не слежу за вами


AOP

я (вдруг вспомнилось): яркая архитектура, говоришь используйAOPУместно ли иметь с ним дело?

яркая архитектура: В общем, для каких действий мы используем АОП?

я: В моем случае он обычно используется для обработки разрешений, печати журнала, синхронизации кеша, специального подсчета сцен и т. д.

яркая архитектура: Да, представьте, как бы это выглядело, если бы мы всю эту бизнес-логику свалили в аспекты? Одна точка разреза — это нормально, а как насчет двух и десяти? Когда все получат новый проект, они будут ссылаться на предыдущий стиль кода.Если вы плохо начнете, другие люди будут следовать тому же принципу, и вскоре код станет похож на паутину, поэтому этого пути следует избегать.


Развязка MQ

я (вдруг вспомнилось): Кстати, у наших новинок/модификаций будет MQ, я пользуюсь только监听MQ然后做业务处理Достаточно.

яркая архитектура: Это определенно осуществимо, но это немного похоже на убийство цыплят ножом мясника.В конце концов, ситуация, с которой нам нужно иметь дело, — это лишь малая часть MQ, а что, если исторический код не отправляет MQ?


Spring Event

яркая архитектура: Вы зналиSpring Event?

я: Я исследовал это раньше, и это действительно вполне уместно использовать здесь.

PS: Spring Event — это механизм уведомления о событиях в системе Spring, и его принцип можно понимать как режим наблюдателя, реализованный Spring.

Примечание. Приведенный выше простой шаблон наблюдателя относится к шаблону наблюдателя, реализованному JDK (1.8).

// 以下为Demo代码
@RestController
public class EventRequest implements ApplicationContextAware {

    private ApplicationContext appContext;

    @RequestMapping("/testEvent")
    public String testEventSave(String name) {
        appContext.publishEvent(new User(this, name));
        return "ok";
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        appContext = applicationContext;
    }
}
// 监听者
@Component
public class WebEventListener {

    /**
     * 仅监听字段值为 foo 时,类为 User.class 时
     */
    @EventListener(classes = User.class, condition = "#event.name == 'foo'")
    public void listen(User event){
        // TODO
    }

    /**
     * 监听 User.class 情况
     */
    @EventListener(classes = User.class)
    public void listen1(User event){
        // TODO
    }
}

яркая архитектура: Да, эта демонстрация может отражать его преимущества.

  1. Мы можем публиковать несколько событий в одном методе, не мешая друг другу
  2. Слушатели могут выполнять базовую фильтрацию на основе выражений
  3. Событие можно прослушивать повторно

я: Да, и он также может поддерживать асинхронную обработку событий!

Яркая архитектура (пауза): Считаете ли вы поддержку асинхронности уникальным преимуществом? Ха-ха-ха, даже если вы слушаете события синхронно, вам просто нужно использовать пул потоков для их асинхронной обработки. Возможность естественной асинхронности — это просто вишенка на торте, не запутайтесь. Конечно, у каждой технологии и функции есть свои уникальные сценарии использования, и вам нужно обращать внимание на их особые обстоятельства при их использовании, такие как:

  1. Разрешена ли асинхронная обработка в бизнесе (даже если она затягивается на долгое время)
  2. Можете ли вы полностью доверять параметрам в уведомлении о событии, нужно ли вам возвращаться и т.д.

Есть ли другой способ

Я счастлив): Если я использую Spring Event, то мне нужно только немного изменить его.Масштабируемость и ремонтопригодность кода всплывут сразу, а мы только что говорили о таком количестве методов и способов, как я чувствую, что это все观察者模式А?

яркая архитектура: Да, будь то JDK или Spring, или AOP, MQ, это все идеи паттерна Observer,毕竟观察者模式的特点就是解耦.

я: Разве мы не можем использовать другие идеи шаблонов проектирования?

яркая архитектура: Конечно можно, но изменений может быть чуть больше, ведь этот класс почти тысячи строк, так что старайтесь добавлять как можно меньше вещей.

я: Например, какие еще методы можно использовать?

яркая архитектура: Гм... если вы хотите это услышать, вот посмотрите на ваш исходный код:

finally {
    SkuMainBean retVal = skuMainBridgeService.updateSkuBridgeMainBean(skuMainBean);
    if(retVal != null){
        // 商品创建/修改异步处理逻辑
        SimpleThreadPool.executeRunnable(SimpleThreadPool.ThreadPoolName.openSkuHandle, () -> {
            skuOperateBusinessService.checkOpenSkuReview(retVal);
        });
    }
}

В этом бизнес-методе это должно бытьskuMainBeanObject, потому что весь метод оперирует им, то мы можем абстрагировать один за другим класс стратегии, а затем использовать фабрику для работы с ним, например, изменить его на это:

// 修改后代码
finally {
    skuMainBeanFactory.checkAndHandle(skuMainBean);
}

// 工厂方法
public void checkAndHandle (SkuMainBean skuMainBean) {
    for (策略集合: 策略) {
        if (check(skuMainBean)) {
        	// TODO
        }
	}
}

яркая архитектура: Как вы думаете, это также очень расширяемо?

я (взволнованно): Да я вдруг чувствую, что этот метод похож на SpringEvent!

Яркая архитектура (улыбается):孺子可教也,这种策略+工厂的方式是基于接口编程,通过check方法判断是否需要处理,而SpringEvent说白了是通过事件的传播,即方法直接调用来判断是否需要处理,本质都是一样的,那你知道未来的新需求你该怎么写了吗?

я (взволнованно): Я вижу, если вы хотите написать масштабируемый код, вы не сможете сделать это так, как код, который я изменил сегодня, это чушь!

Яркая архитектура (качает головой, встает и идет):Kerwin,你错了,你今天改的历史代码在当时可以说是最佳实践了,只是因为你遇到了之前的设计者未考虑到的问题而已。我们讲设计模式、讲七大原则,讲不要过度设计,就是为了你现在出现的情况,我们在编码过程中可能会遇到千奇百怪的代码,我们可以抱怨,可以吐槽,但记住,不要为了某些需求就把本来漂亮的代码变成屎山。所以你需要去学习编程的思想,学习设计的思想。

я (громко):Вот, архитектор! Что, если бы был кусок кода, который был настолько гнилым, что он не мог стать еще более гнилым!


"Тогда рефакторинг! Тогда запиши имя автора и разглагольствуй о нем! 🤪"

Наконец

Просмотрите полный текст, чтобы сделать резюме, если ваше требование состоит в том, чтобы разрешить возврат предварительной проверки, то проверьте и верните без колебаний! Однако, если ваши потребности совпадают с моими, рекомендуются следующие варианты:

  1. Развязка с MQ
  2. Разделение с SpringEvent
  3. Подумайте, нужен ли вам класс стратегии, исходя из ваших текущих потребностей и возможных будущих потребностей.
  4. Окончательное решение: по-настоящему понять семь принципов программирования и часто используемые шаблоны проектирования и соответствующим образом адаптироваться.

Поэтому позвольте мне порекомендовать предыдущую статью:Шаблоны проектирования в целом: от того, зачем нужны принципы, до фактической реализации

Если вы найдете этот контент полезным:

  1. Конечно, ставьте лайки и поддерживайте~
  2. Кроме того, вы можете искать и следить за официальной учетной записью "это Кервин», давайте вместе пойдем по дороге технологий~ 😋