предисловие
делаю это недавно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значение в перехватчик:
Переупорядочить цепочку ответственности:
Суммировать
Весь шаблон цепочки ответственности завершен, и я надеюсь помочь друзьям, которые не знакомы с этим шаблоном проектирования.
Исходный код выше выглядит следующим образом:
Добро пожаловать, чтобы обратить внимание на публичный аккаунт, чтобы общаться вместе: