предисловие
делаю это недавноCicadaФункция перехватчика просто использует шаблон цепочки ответственности.
Частота использования этого шаблона дизайна довольно высока в повседневном использовании, поэтому воспользуйтесь этой возможностью, чтобы проанализировать его.
Модель цепочки ответственности
Давайте посмотрим, что такое паттерн «Цепочка ответственности».
Цитируя объяснение из Википедии:
Шаблон цепочки ответственности — это шаблон проектирования программного обеспечения в объектно-ориентированном программировании, который включает в себя некоторые объекты команд и ряд объектов обработки. Каждый обработчик определяет, какие объекты команд он может обрабатывать, а также знает, как передавать объекты команд, которые он не может обрабатывать, следующему обработчику в цепочке. Шаблон также описывает методы добавления новых объектов обработки в конец цепочки обработки.
Просто прочитав это описание, вы можете запутаться.Короче говоря, этот шаблон проектирования используется для выполнения ряда операций над объектом или запросом, и эта логика обработки просто образует цепочку.
Ниже приводится краткая демонстрация различий и преимуществ использования и отказа от использования шаблона цепочки ответственности.
Применение модели цепочки ответственности
традиционная реализация
Предположим такой сценарий: передается часть контента, и текст необходимо обработать, например отфильтровать деликатные слова, изменить опечатки и, наконец, применить авторские права.
Обычно пишут так:
public class Main {
public static void main(String[] args) {
String msg = "内容内容内容" ;
String result = Process.sensitiveWord()
.typo()
.copyright();
}
}
Кажется, это без проблем решает проблему, но что, если мне еще нужно добавить к контенту унифицированный заголовок? В существующий способ приходится добавлять новый метод обработки, и он есть в этом клиенте (Process
) в зависимости от доп.
Очевидно, что такая масштабируемость не является хорошей.
Реализация шаблона цепочки ответственности
Здесь в игру вступает модель цепочки ответственности.
Это требование очень хорошо согласуется с характеристиками серии обработки объекта и запроса.
Итак, модифицируем код:
В настоящее времяProcess
Это интерфейс, используемый для определения реальной функции обработки.
public interface Process {
/**
* 执行处理
* @param msg
*/
void doProcess(String msg) ;
}
При этом вся предыдущая обработка контента нуждается только в реализации этого интерфейса:
public class SensitiveWordProcess implements Process {
@Override
public void doProcess(String msg) {
System.out.println(msg + "敏感词处理");
}
}
public class CopyrightProcess implements Process {
@Override
public void doProcess(String msg) {
System.out.println(msg + "版权处理");
}
}
public class CopyrightProcess implements Process {
@Override
public void doProcess(String msg) {
System.out.println(msg + "版权处理");
}
}
Затем вам нужно только предоставить клиенту запись об исполнении и запись для добавления цепочки ответственности:
public class MsgProcessChain {
private List<Process> chains = new ArrayList<>() ;
/**
* 添加责任链
* @param process
* @return
*/
public MsgProcessChain addChain(Process process){
chains.add(process) ;
return this ;
}
/**
* 执行处理
* @param msg
*/
public void process(String msg){
for (Process chain : chains) {
chain.doProcess(msg);
}
}
}
Это очень просто использовать:
public class Main {
public static void main(String[] args) {
String msg = "内容内容内容==" ;
MsgProcessChain chain = new MsgProcessChain()
.addChain(new SensitiveWordProcess())
.addChain(new TypoProcess())
.addChain(new CopyrightProcess()) ;
chain.process(msg) ;
}
}
Когда мне нужно добавить другую логику обработки, мне нужно добавить только блок обработки (addChain(Process process)
), а клиентуchain.process(msg)
Он незаметен и не требует никаких изменений.
Возможно, вы не написали код, напрямую связанный с моделью цепочки ответственности, но использовали его непреднамеренно.
НапримерNetty
серединаpipeline
Это типичный шаблон цепочки ответственности, который позволяет запросу проходить через весь конвейер.
Из официальной схемы ясно видно, что это модель цепочки ответственности:
Разработайте перехватчик с помощью шаблона цепочки ответственности
Использование шаблона цепочки ответственности для перехватчиков не может быть лучше.
Давайте посмотрим наCicada
Реализация в:
Во-первых, определить и вышеProcess
аналогичный интерфейсCicadaInterceptor
Абстрактный класс:
public abstract class CicadaInterceptor {
public boolean before(CicadaContext context,Param param) throws Exception{
return true;
}
public void after(CicadaContext context,Param param) throws Exception{}
}
также определяетInterceptProcess
клиент:
один из нихloadInterceptors()
Все перехватчики будут добавлены в цепочку ответственности.
Предусмотрены еще две функции, соответствующие записи до и после перехвата:
практическое применение
Теперь давайте посмотрим, как он используется.
по запросуhandle
загрузить сначала(loadInterceptors(AppConfig appConfig)
), то есть инициализировать цепочку ответственности.
Далее идет вход клиента, может вызываться метод входа до и после перехвата.
Так как это перехватчик, то в
before
Запрос может быть перехвачен в функции. просто вернисьfalse
Он не будет продолжать обработку в обратном направлении. Итак, вот оценка возвращаемого значения.
В то же время пользователям нужно только создать наследование класса перехватчикаCicadaInterceptor
класс подойдет.
Вот демо с двумя перехватчиками:
- записывать бизнес
handle
время исполнения. - существует
after
Параметры запроса распечатываются. - При этом можно вернуться в первый перехватчик
false
Пусть запрос будет перехвачен.
Сначала проведем первые два теста:
Таким образом, когда я запрашиваю один из интерфейсов, журнал только что будет распечатан:
Далее я позволяю перехватчику, который печатает время выполнения, перехватывать запрос, а заодно ввожу во фронтенд кусок текста:
В интерфейсе запроса можно увидеть следующее:
При этом следующие параметры запроса не выводятся, что говорит о том, что запрос действительно перехвачен.
При этом я тоже могу настроить порядок перехвата, просто нужно@Interceptor(order = 1)
определите это в аннотацииorder
свойство (значение по умолчанию равно 0, чем меньше значение, тем выполняется первым).
Раньше перехватчик, выводивший параметры запроса, выполнялся первым, в этот раз я вручную настроил его порядок на 2, а порядок времени печати на 1.
Снова запросите интерфейс, чтобы просмотреть фоновый журнал:
Перехватчик, который находит время выполнения печати, выполняется первым.
Как этот порядок выполнения реализует пользовательскую конфигурацию?
На самом деле, это относительно просто, со следующими шагами:
- При загрузке перехватчика аннотация будет
order
сохрани это. - При постановке перехватчика в цепочку ответственности отражение будет
order
Значение сохраняется для каждого перехватчика. - Наконец, измените порядок этой цепочки ответственности путем сортировки.
Опубликуйте основной код.
Сохранить при сканировании перехватчиковorder
ценность:
спастиorder
значение в перехватчик:
Переупорядочить цепочку ответственности:
Суммировать
Весь шаблон цепочки ответственности завершен, и я надеюсь помочь друзьям, которые не знакомы с этим шаблоном проектирования.
Исходный код выше выглядит следующим образом:
Добро пожаловать, чтобы обратить внимание на публичный аккаунт, чтобы общаться вместе: