Статьи

Шаблон проектирования цепочки ответственности в Java

В этом уроке мы узнаем, как реализовать шаблон цепочки ответственности в Java.

Шаблон проектирования « Цепочка ответственности» предполагает наличие цепочки объектов, которые вместе отвечают за обработку запроса. Когда клиент отправляет запрос, первый обработчик попытается обработать его. Если это может обработать это, тогда обработка запроса заканчивается здесь. Однако, если обработчик не может обработать запрос пользователя, он перейдет к следующему обработчику в цепочке. Этот процесс будет продолжаться до тех пор, пока один из обработчиков в цепочке не успешно обработает запрос или цепочка не завершится. Если вся цепочка не может обработать запрос, это означает, что запрос остается неудовлетворенным.

Зачем использовать цепь ответственности?

Цепочка ответственности — довольно важный шаблон проектирования в нашей индустрии программного обеспечения. Он предлагает несколько преимуществ:

  • Это способствует слабой связи между пользователем и системой, поскольку пользователю не нужно заботиться о том, какой объект обработает его запрос.
  • Механизм обработки исключений Java также использует этот шаблон. Если подходящий блок catch не найден, запрос передается методу вызывающей стороны для обработки, пока мы не найдем подходящий обработчик.
  • Этот шаблон также находит применение в фильтрации пользовательских запросов, пропуская запрос через цепочку фильтров.

Представление UML:

UML-представление шаблона цепочки ответственности выглядит следующим образом:

Здесь у нас есть следующие типы объектов:

  • Клиент: код, делающий запросы пользователя
  • Обработчик: абстрактный суперкласс или интерфейс, определяющий метод обработчика запроса.
  • ConcreteHandler: классы реализации для обработчика

Объекты-обработчики связаны между собой в цепочке. Кроме того, каждый конкретный обработчик обрабатывает запрос по-своему.

Определение абстрактного обработчика:

Давайте реализуем логику фильтрации запросов, используя Chain Of Responsibility.

Во-первых, мы определим абстрактный класс RequestFilter :

01
02
03
04
05
06
07
08
09
10
11
12
public abstract class RequestFilter {
     
    private RequestFilter next;
  
    public RequestFilter(RequestFilter next) {
        this.next = next;
    }
  
    public boolean doFilter(HttpServletRequest request);
     
    public void getNext() { return this.next; }
}

Определение конкретных обработчиков:

Теперь давайте определим самый первый класс фильтра в цепочке, который будет блокировать запрос от подозрительных IP-адресов:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public class SuspiciousRequestFilter extends RequestFilter {
     
    public SuspiciousRequestFilter(RequestFilter next) {
        super(next);
    }
   
    public boolean doFilter(HttpServletRequest request) {
        if(hasMaliciousIntent(request.getRemoteAddr()) {
            //blocks the request
            return false;
        } else if(next == null) {
            //filter chain ended
            return false;
        }
        return this.getNext().doFilter(request);
    }
  
    public boolean hasMaliciousIntent(String ipAddress) {  ... }
}

Аналогично, давайте определим второй фильтр нашей цепочки, который будет блокировать неавторизованные запросы:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public class UnauthorizedRequestFilter extends RequestFilter {
     
    public UnauthorizedRequestFilter(RequestFilter next) {
        super(next);
    }
   
    public boolean doFilter(HttpServletRequest request) {
        if(isUserUnauthorized(request)) {
            //blocks the request
            return false;
        } else if(next == null) {
            //filter chain ended
            return false;
        }
        return this.getNext().doFilter(request);
    }
  
    public boolean isUserUnauthorized(HttpServletRequest request) {  ... }
}

И самый последний фильтр, который будет идентифицировать и блокировать пользователей с превышенными попытками входа в систему:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public class ExceededLoginAttemptsRequestFilter extends RequestFilter {
     
    public ExceededLoginAttemptsRequestFilter(RequestFilter next) {
        super(next);
    }
   
    public boolean doFilter(HttpServletRequest request) {
        if(hasExceededLoginAttempts(request)) {
            //blocks the request
            return false;
        } else if(next == null) {
            //filter chain ended
            return false;
        }
        return this.getNext().doFilter(request);
    }
  
    public boolean hasExceededLoginAttempts(HttpServletRequest request) {  ... }
}

Вызов Цепи:

Наконец, пришло время связать их вместе в цепочку:

1
2
3
4
5
6
7
8
9
HttpServletRequest httpServletRequest = ...
  
//the last filter in our chain
RequestFilter exceededAttemptsFilter = new ExceededLoginAttemptsRequestFilter(null);
  
RequestFilter unauthorizedFilter = new UnauthorizedRequestFilter(exceededAttemptsFilter);
RequestFilter suspiciousActivityFilter = new SuspiciousRequestFilter(unauthorizedFilter);
  
suspiciousActivityFilter.doFilter(httpServletRequest);

Здесь каждый пользовательский запрос будет следовать следующей цепочке фильтрации:

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

Вывод:

В этом уроке мы узнали, как и когда использовать шаблон проектирования «Цепочка ответственности».

Опубликовано на Java Code Geeks с разрешения Шубхры Шриваставы, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Шаблон проектирования Chain Of Responsibility In Java

Мнения, высказанные участниками Java Code Geeks, являются их собственными.