Статьи

Декорирование конвертов

Иногда Очень часто мне нужен класс, который реализует интерфейс путем создания экземпляра другого класса. Звучит странно? Позвольте мне показать вам пример. В Takes Framework есть много таких классов, и все они названы как *Wrap . Это удобная концепция дизайна, которая, к сожалению, в Java выглядит довольно многословно. Было бы здорово иметь что-то более короткое, например, в EO .

Север Северо-западом (1959) Альфредом Хичкоком

Взгляните на RsHtml от Takes Framework . Его дизайн выглядит следующим образом (упрощенная версия с одним основным конструктором):

01
02
03
04
05
06
07
08
09
10
class RsHtml extends RsWrap {
  RsHtml(final String text) {
    super(
      new RsWithType(
        new RsWithStatus(text, 200),
        "text/html"
      )
    );
  }
}

Теперь давайте посмотрим, что расширяет RsWrap :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
public class RsWrap implements Response {
  private final Response origin;
  public RsWrap(final Response res) {
    this.origin = res;
  }
  @Override
  public final Iterable<String> head() {
    return this.origin.head();
  }
  @Override
  public final InputStream body() {
    return this.origin.body();
  }
}

Как видите, этот «декоратор» ничего не делает, кроме «просто декорирования». Он инкапсулирует другой Response и проходит через все вызовы методов.

Если пока не ясно, я объясню назначение RsHtml . Допустим, у вас есть текст, и вы хотите создать Response :

1
2
3
4
5
String text = // you have it already
Response response = new RsWithType(
  new RsWithStatus(text, HttpURLConnection.HTTP_OK),
  "text/html"
);

Вместо того, чтобы многократно RsHtml эту композицию декораторов во многих местах, вы используете RsHtml :

1
2
String text = // you have it already
Response response = new RsHtml(text);

Это очень удобно, но этот RsWrap очень многословен. Слишком много строк, которые не делают ничего особенного; они просто перенаправляют все вызовы методов в инкапсулированный Response .

Как насчет того, чтобы мы представили новую концепцию «декораторы» с новым ключевым словом decorates :

01
02
03
04
05
06
07
08
09
10
class RsHtml decorates Response {
  RsHtml(final String text) {
    this(
      new RsWithType(
        new RsWithStatus(text, 200),
        "text/html"
      )
    )
  }
}

Затем, чтобы создать объект, мы просто вызываем:

1
Response response = new RsHtml(text);

У нас нет новых методов в декораторах, только конструкторы. Единственная цель для этих парней — создавать другие объекты и инкапсулировать их. Они на самом деле не являются объектами полного назначения. Они только помогают нам создавать другие объекты.

Вот почему я бы назвал их «украшением конвертов».

Эта идея может выглядеть очень похожей на шаблон проектирования Factory , но в ней нет статических методов , которых мы стараемся избегать в объектно-ориентированном программировании .

Вы можете также найти эти связанные посты интересными: Композитные декораторы против императивных утилитарных методов ; Защитное программирование через валидацию декораторов ; If-Then-Else — это запах кода ; Вертикальная и горизонтальная отделка ; Почему дизайн InputStream неправильный ;

Ссылка: Оформление конвертов от нашего партнера по JCG Егора Бугаенко в блоге About Programming .