Статьи

Образец Декоратора

Образец Декоратора

украшения Одним из шаблонов дизайна, который я не вижу часто используемым, является Decorator . Я не уверен, почему этот шаблон не так популярен, так как он очень удобен. Шаблон Decorator позволяет добавлять функциональные возможности к объекту контролируемым образом. Это работает во время выполнения, даже со статически типизированными языками! Шаблон декоратора является альтернативой подклассам. Подклассы добавляют поведение во время компиляции, и изменение влияет на все экземпляры исходного класса; Декорирование может обеспечить новое поведение во время выполнения для отдельных объектов. Шаблон Decorator — хороший инструмент для соблюдения принципа открытия / закрытия .

Некоторые примеры могут показать значение этого шаблона:

Пример 1: HTTP-аутентификация

Представьте себе HTTP-клиент, например тот, который общается с сервисом RESTful.

Некоторые части службы общедоступны, но некоторые требуют, чтобы пользователь вошел в систему. Служба RESTful отвечает 401 Unauthorized кодом 401 Unauthorized статуса, когда клиент пытается получить доступ к защищенному ресурсу.

Изменение клиента для обработки 401 приводит к дублированию, поскольку каждый вызов потенциально может потребовать аутентификации . Таким образом, мы должны извлечь код аутентификации в одном месте. Где это место?

Вот где появляется шаблон Decorator:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class AuthenticatingHttpClient
    implements HttpClient {
 
  private final HttpClient wrapped;
 
  public AuthenticatingHttpClient(HttpClient wrapped) {
    this.wrapped = wrapped;
  }
 
  @Override
  public Response execute(Request request) {
    Response response = wrapped.execute(request);
    if (response.getStatusCode() == 401) {
      authenticate();
      response = wrapped.execute(request);
    }
    return response;
  }
 
  protected void authenticate() {
    // ...
  }
 
}

Клиент REST теперь никогда не должен беспокоиться об аутентификации, так как AuthenticatingHttpClient обрабатывает это.

Пример 2: Кэширование авторизационных решений

Итак, пользователь вошел в систему, и REST-сервер знает свою личность. Может быть принято решение разрешить доступ к определенному ресурсу одному человеку, но не другому.

Я могу реализовать авторизацию , возможно, используя XACML . В этом случае точка принятия решения о политике (PDP) отвечает за принятие решений о доступе.

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

Это еще один случай, когда шаблон Decorator может пригодиться:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class CachingPdp implements Pdp {
 
  private final Pdp wrapped;
 
  public CachingPdp(Pdp wrapped) {
    this.wrapped = wrapped;
  }
 
  @Override
  public ResponseContext decide(
      RequestContext request) {
    ResponseContext response = getCached(request);
    if (response == null) {
      response = wrapped.decide(request);
      cache(request, response);
    }
    return response;
  }
 
  protected ResponseContext getCached(
      RequestContext request) {
    // ...
  }
 
  protected void cache(RequestContext request,
      ResponseContext response) {
    // ...
  }
 
}

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

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

Если вы посмотрите внимательно, я уверен, что вы сможете найти гораздо больше возможностей для применения этого шаблона.

Ссылка: шаблон Decorator от нашего партнера по JCG Ремона Синнема в блоге по безопасной разработке программного обеспечения .