Рубрики
Без рубрики

Структурные шаблоны в ядре Java

Автор оригинала: baeldung.

1. Обзор

Структурные шаблоны проектирования – это те, которые упрощают проектирование структур больших объектов путем выявления связей между ними. Они описывают общие способы составления классов и объектов, чтобы они стали повторяемыми в качестве решений.

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

2. Адаптер

Адаптер, как следует из названия, выступает в качестве посредника для преобразования несовместимого в противном случае интерфейса в тот, который ожидает клиент .

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

Jdk collection framework предлагает множество примеров шаблона адаптера:

List musketeers = Arrays.asList("Athos", "Aramis", "Porthos");

Здесь Массивы#asList помогают нам адаптировать Массив к Списку .

Структура ввода-вывода также широко использует этот шаблон. В качестве примера рассмотрим этот фрагмент кода, который сопоставляет входной поток с объектом чтения:

InputStreamReader input = new InputStreamReader(new FileInputStream("input.txt"));

3. Мост

Шаблон моста позволяет разделить абстракции и реализации таким образом, чтобы они могли развиваться независимо друг от друга, но при этом иметь возможность сосуществовать и взаимодействовать|/.

Примером этого в Java может служить API JDBC . Он действует как связующее звено между базами данных, такими как Oracle, MySQL и PostgreSQL, и их конкретными реализациями.

API JDBC – это набор стандартных интерфейсов, таких как Драйвер , Соединение и Набор результатов, и многие другие. Это позволяет различным поставщикам баз данных иметь свои отдельные реализации.

Например, чтобы создать соединение с базой данных, мы бы сказали:

Connection connection = DriverManager.getConnection(url);

Здесь url – это строка, которая может представлять любого поставщика базы данных.

Например, для PostgreSQL мы могли бы иметь:

String url = "jdbc:postgresql://localhost/demo";

И для MySQL:

String url = "jdbc:mysql://localhost/demo";

4. Композитный

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

Вложенные контейнеры в AWT/Swing являются отличными примерами использования составного шаблона в ядре Java. Объект java.awt.Container в основном является корневым компонентом, который может содержать другие компоненты, образуя древовидную структуру вложенных компонентов.

Рассмотрим этот фрагмент кода:

JTabbedPane pane = new JTabbedPane();
pane.addTab("1", new Container());
pane.addTab("2", new JButton());
pane.addTab("3", new JCheckBox());

Все классы, используемые здесь, а именно JTabbedPane , JButton , JCheckBox и JFrame , являются потомками Контейнера . Как мы видим, этот фрагмент кода обрабатывает корень дерева или Контейнер во второй строке так же, как он обрабатывает свои дочерние элементы .

5. Декоратор

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

Одно из самых распространенных применений этого паттерна можно найти в java.io упаковка:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("test.txt")));
while (bis.available() > 0) {
    char c = (char) bis.read();
    System.out.println("Char: " + c);
}

Здесь BufferedInputStream украшает FileInputStream , чтобы добавить возможность буферизации входных данных . Примечательно, что оба этих класса имеют InputStream в качестве общего предка. Это означает, что и объект, который украшает, и объект, который украшается, относятся к одному и тому же типу. Это безошибочный показатель рисунка декоратора.

6. Фасад

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

Этот шаблон вступает в игру, когда мы хотим упростить или скрыть сложность подсистемы или фреймворка.

API Faces Внешний контекст является отличным примером шаблона фасада. Он использует такие классы, как HttpServletRequest , HttpServletResponse и HttpSession внутренне. По сути, это класс, который позволяет API Faces быть в блаженном неведении о своей базовой среде приложения.

Давайте посмотрим , как Primefaces использует его для написания Http-ответа , фактически не зная об этом :

protected void writePDFToResponse(ExternalContext externalContext, ByteArrayOutputStream baos, String fileName)
  throws IOException, DocumentException {
    externalContext.setResponseContentType("application/pdf");
    externalContext.setResponseHeader("Expires", "0");
    // set more relevant headers
    externalContext.setResponseContentLength(baos.size());
    externalContext.addResponseCookie(
      Constants.DOWNLOAD_COOKIE, "true", Collections.emptyMap());
    OutputStream out = externalContext.getResponseOutputStream();
    baos.writeTo(out);
    // do cleanup
}

Как мы можем видеть здесь, мы устанавливаем заголовки ответов, фактический ответ и файл cookie непосредственно, используя ExternalContext в качестве фасада. HTTP-ответ отсутствует на картинке .

7. Летный вес

Шаблон flyweight снимает вес или объем памяти с наших объектов, перерабатывая их . Другими словами, если у нас есть неизменяемые объекты, которые могут совместно использовать состояние в соответствии с этим шаблоном, мы можем кэшировать их для повышения производительности системы.

Flyweight можно обнаружить во всех классах чисел в Java.

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

Например, Integer имеет статический класс IntegerCache, который помогает его методу valueOf всегда кэшировать значения в диапазоне от -128 до 127:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high) {
        return IntegerCache.cache[i + (-IntegerCache.low)];
    }
    return new Integer(i);
}

8. Прокси

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

Используя этот шаблон, становится легко выполнить любую операцию с исходным объектом до или после его создания.

JDK предоставляет класс java.lang.reflect.Proxy из коробки для реализаций прокси:

Foo proxyFoo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
  new Class[] { Foo.class }, handler);

Приведенный выше фрагмент кода создает прокси-сервер proxy Foo для интерфейса Foo .

9. Заключение

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

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