Перейти к содержимому

Что такое паттерны в java

  • автор:

Структурные паттерны проектирования: для каких задач нужны, виды и примеры реализации

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

Еще раз про паттерны

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

Всего существует 23 классических паттерна, которые были описаны в книге «Банды четырех». В зависимости от того, какие задачи они решают, делятся на порождающие, структурные и поведенческие.

Структурные паттерны

Согласно Википедии, структурные шаблоны (structural patterns) — шаблоны проектирования, в которых рассматривается вопрос о том, как из классов и объектов образуются более крупные структуры.

Проще говоря, структурные паттерны связаны с композицией объектов или тем, как сущности могут использовать друг друга. К ним относятся:

  • Facade, или Фасад
  • Adapter, или Адаптер
  • Decorator, или Декоратор
  • Bridge, или Мост
  • Composite, или Компоновщик
  • Front controller, или Единая точка входа
  • Flyweight, или Приспособленец, или Лекговес
  • Proxy, или Заместитель

3 самых популярных структурных паттерна

По мнению разработчиков MediaSoft Facade, Adaptor и Decorator — это самые используемые структурные паттерны в разработке. Давайте разберемся, с какими задачами они помогают справляться, и посмотрим на примеры их реализации.

Facade (Фасад)

Согласно Википедии, Facade — структурный шаблон проектирования, позволяющий скрыть сложность системы путём сведения всех возможных внешних вызовов к одному объекту, делегирующему их соответствующим объектам системы.

Проще говоря: Facade предоставляет упрощенный интерфейс для сложной системы.

Еще проще: При оплате покупки через Apple Pay вы подносите телефон к устройству и оплачиваете покупку. Кажется, что все просто. Но на самом деле внутри этого процесса происходит гораздо больше вещей. Этот упрощенный интерфейс называется фасадом.

Когда нужен: Используется в библиотеках и позволяет описать их так, чтобы пользователю не нужно было вникать в их реализацию.

Структура паттерна:

  1. Фасад — интерфейс для легкого доступа. Предоставляет только тот функционал, который нужен клиенту, и скрывает всё остальное.
  2. Сложная система из классов и методов.

Как создать:

  1. Создаем интерфейс фасада. В нем перечисляем нужные нам методы системы, которые предоставляет фасад.
  2. Создаем класс фасада, который реализует этот интерфейс.
  3. В методах этого класса реализуем обращения к сложной системе, которая скрывается за фасадом.

Пример реализации:

class CPU < public void execute() < . >> class Memory < public void load(long position, byte[] data) < . >> class HardDrive < public byte[] read(long lba, int size) < . >> class Computer < // Facade private CPU cpu = new CPU(); private Memory memory = new Memory(); private HardDrive hardDrive = new HardDrive(); public void startComputer() < memory.load(BOOT_ADDRESS, hardDrive.read(BOOT_SECTOR, SECTOR_SIZE)); cpu.execute(); >> class Application < // Client public static void main(String[] args) < Computer computer = new Computer(); computer.startComputer(); >>
// Создаем классы, Doors и Body, которые отвечают за конфигурацию отдельных частей автомобиля class Doors < getNumberOfDoors(type) < return type === 'truck' ? 2 : 4; >> class Body < createBody(type) < return type === 'truck'; >> // Далее создаем класс Car, который и является нашим фасадом. В методе creacteCar мы создали экземпляры классов и вызвали нужные методы у них, чтобы получить готовую конфигурацию автомобиля. Таким образом мы оградили пользователя от нужды понимания всех классов и их взаимодействия. Взамен этого предложили удобный интерфейс class Car < createCar(type) < const doors = new Doors().getNumberOfDoors(type); const body = new Body().createBody(type); return ; > > console.log(new Car().createCar('truck')); // < doors: 2, body: true >console.log(new Car().createCar('sport')); //

Adapter (Адаптер)

Согласно Википедии, Adapter — структурный шаблон проектирования, предназначенный для организации использования функций объекта, недоступного для модификации, через специально созданный интерфейс.

Проще говоря, Adapter позволяет объектам с несовместимыми интерфейсами работать вместе.

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

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

Существует два варианта этого паттерна:

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

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

Как создать:

  1. Создаем класс Адаптера.
  2. В этом классе реализуем метод, который принимает на входе объект в незнакомом формате, а возвращает объект нужного нам формата.
  3. В этом методе реализуем логику преобразования объекта одного формата в другой.

Пример реализации:

interface Chief < Object makeBreakfast(); Object makeDinner(); >public class Plumber < // Adaptee public Object getScrewNut() < . >public Object getGasket() < . >> public class ChiefAdapter extends Plumber implements Chief < // Adapter public Object makeBreakfast() < return getGasket(); >public Object makeDinner() < return getScrewNut(); >> public class Client < // Client public static void eat(Object dish) < . >public static void main(String[] args) < Chief ch = new ChiefAdapter(); eat(ch.makeBreakfast()); eat(ch.makeDinner()); >>
// У нас есть класс калькулятора, который реализует единственный метод "operation" class Calculator < operation(num1, num2, operation) < switch (operation) < case 'multiplication': return num1 * num2; case 'division': return num1 / num2; default: return NaN; >> > // Допустим нам нужно создать улучшенную версию калькулятора class NewCalculator < add(num1, num2) < return num1 + num2; >div(num1, num2) < return num1 / num2; >mult(num1, num2) < return num1 * num2; >> // Но возникает проблема, что нет обратной совместимости со старым калькулятором, как раз в этом нам и поможет адаптер. Мы адаптируем новый калькулятор под функционал старого class CalculatorAdapter < constructor() < this.calculator = new NewCalculator(); >operation(num1, num2, operation) < switch (operation) < case "add": return this.calculator.add(num1, num2); case "multiplication": return this.calculator.mult(num1, num2); case "division": return this.calculator.div(num1, num2); default: return NaN; >> > // Обратите внимание, мы используем адаптер вместо старого калькулятора const calcAdapter = new CalculatorAdapter(); const sumAdapter = calcAdapter.operation(2, 2, "multiplication"); console.log(sumAdapter); // А новый функционал используем от экземпляра класса нового калькулятора const calculator = new Calculator(); const sum = calculator.mult(2, 2); console.log(sum);

Decorator (Декоратор)

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

Проще говоря, паттерн позволяет добавлять объектам новые функции с помощью обертки без создания отдельного класса.

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

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

Структура:

  1. Компонент с заданным интерфейсом
  2. Декоратор, который оборачивает компонент и добавляет новое поведение.

Как создать:

  1. Создаем интерфейс. В нем перечисляем методы библиотеки, с которой будет работать декоратор.
  2. Создаем класс, реализующий этот интерфейс. В нем прописываем логику обращения к объекту, который скрывается за декоратором, и добавляем свою кастомную логику.

Пример реализации:

public interface InterfaceComponent < void doOperation(); >class MainComponent implements InterfaceComponent < public void doOperation() < System.out.print("World!"); >> abstract class Decorator implements InterfaceComponent < protected InterfaceComponent component; public Decorator (InterfaceComponent c) < component = c; >public void doOperation() < component.doOperation(); >public void newOperation() < System.out.println("Do Nothing"); >> class DecoratorComma extends Decorator < public DecoratorComma(InterfaceComponent c) < super(c); >public void doOperation() < System.out.print(","); super.doOperation(); >public void newOperation() < System.out.println("New comma operation"); >> class DecoratorHello extends Decorator < public DecoratorHello(InterfaceComponent c) < super(c); >public void doOperation() < System.out.print("Hello"); super.doOperation(); >public void newOperation() < System.out.println("New hello operation"); >> class Main < public static void main (String. s) < Decorator c = new DecoratorHello(new DecoratorComma(new MainComponent())); c.doOperation(); // Результат выполнения программы "Hello,World!" c.newOperation(); // New hello operation >>
// создаем класс, с набором свойств и методов class Car < constructor(cost) < this.cost = cost; >getCost() < return `Стоимость автомобиля: $`; > > // далее создаем декоратор, который принимает экземпляр класса // и расширяет его, в данном случае добавляем свойство color const colorCar = (car, color) => < car.color = color; return car; >const car = new Car(16000); // оборачиваем инстанс car в декоратор, и получаем расширенный класс colorCar(car, 'orange') console.log(car); // Car < cost: 16000, color: 'orange' >console.log(car.getCost()); // Стоимость автомобиля: 16000 

Заключение

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

В зависимости от того, какие задачи решают паттерны проектирования, они делятся на три вида: порождающие, структурные и поведенческие.

Структурные паттерны связаны с композицией объектов или тем, как сущности могут использовать друг друга. Три самых популярных из них:

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

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

Decorator, или Декоратор, позволяет добавлять объектам новые функции с помощью обертки без создания отдельного класса. Им пользуются каждый раз, когда нужно добавить логику в уже созданные объекты и библиотеки, менять которые нельзя.

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

Паттерны проектирования в Java [Часть 1]

Java-университет

Паттерны проектирования в Java [Часть 1] - 1

Это краткая статья по паттернам проектирования в Java. Реализации паттернов не будет, тут только список паттернов которые есть в java и их краткое содержание. Она будет полезна тем, кто уже в теме, для повторения и обобщения. Или напротив, для тех, кто первый раз подошёл к паттернам — для самого первого обзора темы, прежде, чем копнуть глубже. Паттерны проектирования (шаблоны проектирования) — это готовые к использованию решения часто возникающих в программировании задач. Это не класс и не библиотека, которую можно подключить к проекту, это нечто большее. Паттерны проектирования, подходящий под задачу, реализуется в каждом конкретном случае. Следует, помнить, что такой паттерн, будучи примененным неправильно или к неподходящей задаче, может принести немало проблем. Тем не менее, правильно примененный паттерн поможет решить задачу легко и просто. Типы паттернов:

  • порождающие
  • структурные
  • поведенческие

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

  • Singleton (Одиночка) — ограничивает создание одного экземпляра класса, обеспечивает доступ к его единственному объекту.
  • Factory (Фабрика) — используется, когда у нас есть суперкласс с несколькими подклассами и на основе ввода, нам нужно вернуть один из подкласса.
  • Abstract Factory (Абстрактная фабрика) — используем супер фабрику для создания фабрики, затем используем созданную фабрику для создания объектов.
  • Builder (Строитель) — используется для создания сложного объекта с использованием простых объектов. Постепенно он создает больший объект от малого и простого объекта.
  • Prototype (Прототип) — помогает создать дублированный объект с лучшей производительностью, вместо нового создается возвращаемый клон существующего объекта.

Структурные:

  • Adapter (Адаптер) — это конвертер между двумя несовместимыми объектами. Используя паттерн адаптера, мы можем объединить два несовместимых интерфейса.
  • Composite (Компоновщик) — использует один класс для представления древовидной структуры.
  • Proxy (Заместитель) — представляет функциональность другого класса.
  • Flyweight (Легковес) — вместо создания большого количества похожих объектов, объекты используются повторно.
  • Facade (Фасад) — беспечивает простой интерфейс для клиента, и клиент использует интерфейс для взаимодействия с системой.
  • Bridge (Мост) — делает конкретные классы независимыми от классов реализации интерфейса.
  • Decorator (Декоратор) — добавляет новые функциональные возможности существующего объекта без привязки его структуры.

Поведенческие:

  • Template Method (Шаблонный метод) — определяющий основу алгоритма и позволяющий наследникам переопределять некоторые шаги алгоритма, не изменяя его структуру в целом.
  • Mediator (Посредник) — предоставляет класс посредника, который обрабатывает все коммуникации между различными классами.
  • Chain of Responsibility (Цепочка обязанностей) — позволяет избежать жесткой зависимости отправителя запроса от его получателя, при этом запрос может быть обработан несколькими объектами.
  • Observer (Наблюдатель) — позволяет одним обьектам следить и реагировать на события, происходящие в других объектах.
  • Strategy (Стратегия) — алгоритм стратегии может быть изменен во время выполнения программы.
  • Command (Команда) — интерфейс команды объявляет метод для выполнения определенного действия.
  • State (Состояние) — объект может изменять свое поведение в зависимости от его состояния.
  • Visitor (Посетитель) — используется для упрощения операций над группировками связанных объектов.
  • Interpreter (Интерпретатор) — определяет грамматику простого языка для проблемной области.
  • Iterator (Итератор) — последовательно осуществляет доступ к элементам объекта коллекции, не зная его основного представления.
  • Memento (Хранитель) — используется для хранения состояния объекта, позже это состояние можно восстановить.

Проходя курс JavaRush вы встретите пару паттернов из этого списка. Рекомендую задачи по паттернам: 1522, 1530, 1631, big01, 2912, 3107. Разумное использование паттернов проектирования приводит к повышению надежности обслуживания кода, поскольку в дополнение к тому, чтобы быть хорошим решением общей проблемы, паттерны проектирования могут быть распознаны другими разработчиками, что уменьшает время при работе с определенным кодом. Паттерны проектирования в Java [Часть 2]

Паттерны проектирования

Данной статьей мы начинаем серию статей, посвященных паттернам проектирования.

Статьи рассчитаны на тех, кто уже хорошо знает ООП.

Что такое паттерны в программировании

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

Паттерн — это повторяющийся элемент в различных сферах жизни.

Пример 1: окрас тигра — это паттерн.

Пример 2: Коробка передач — это паттерн.

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

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

Шаблон проектирования / шаблон программирования / паттерн — это типичные способы решения часто возникающих задач в сфере разработки ПО.

ВАЖНО:

Паттерн — это не готовое решение, которое можно откуда-то скопировать и вставить в Вашу программу. Это только общие принципы, которые надо уметь правильно применить.

Мне надо знать паттерны?

  • Паттерны очень часто применяются на практике. Конечно, для начинающих программистов понимание паттернов не всегда заходит легко. Так что наберитесь терпения и учим, учим, учим.
  • Паттерны часто спрашивают на собеседованиях.
  • И самое главное — паттерны предлагают Вам готовые решения. Они помогут Вам сохранить время и усилия, а качество программы повысится.

Откуда они взялись

Хотя сама идея паттернов далеко не новая, популярной она стала после выхода книги «Приёмы объектно-ориентированного проектирования. Паттерны проектирования«. Это произошло в 1994 году. С тех пор мир захватила «шаблономания» ��

Какие они бывают

Есть основные три категории паттернов:

  • Порождающие (Creational Design Patterns)

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

  • Структурные (Structural Design Patterns)

Отвечают за иерархию классов и интерфейсов. Например, «как заставить объекты с несовместимыми интерфейсами работа вместе»?

  • Поведенческие (Behavioral Design Patterns)

Помогает добиться нужного поведения от объектов. Например, «как сделать так, чтобы объекты одного класса следили за изменениями в других классах и реагировали на них»?

Из чего состоит паттерн?

  • Имя
  • Задача, которую решает паттерн
  • Решение:
    • Структуры классов, составляющих решение;
    • Примера на одном из языков программирования;

    А конкретнее?

    Существует 23 классических шаблона проектирования, с которых все и началось. В настоящий момент паттернов намного больше — минимум в 2-3 раза больше.

    Здесь о каждом из них мы, конечно, говорить не будем — это много �� Но мы расскажем об основных паттернах в будущих статьях.

    Самыми-самыми «базовыми» шаблонами проектирования можно назвать следующие:

    С них можно начинать изучение паттернов. Ниже в этой статье Вы найдете ссылочки на статьи по этим паттернам.

    Что следует знать

    Одинаковые ли шаблоны для всех языков программирования?

    Да, в целом понятия паттернов не привязано к конкретному языку. Тем не менее, когда говорят о паттернах, чаще всего имеют ввиду объектно-ориентированные языки программирования.

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

    Да, конечно. Останется только всем о нем рассказать ��

    Это все, что мы хотели Вам рассказать в данной статье.

    Статьи, посвященные конкретным паттернам, Вы найдете по этим ссылочкам:

    • Паттерн Singleton — Часть 1
    • Паттерн Singleton — Часть 2
    • Паттерн Builder
    • Паттерн Factory — Часть 1

    Надеемся, наша статья была Вам полезна. Также есть возможность записаться на наши курсы. Детальнее у на сайте.

    • ← Правила наследования в Java
    • Методы в Java →

    Какие существуют паттерны проектирования на Java

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

    Алексей Кодов
    Автор статьи
    7 июня 2023 в 16:12

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

    1. Порождающие паттерны

    Эти паттерны относятся к процессу создания объектов. Они обеспечивают гибкость и повторное использование кода при создании объектов. Вот некоторые из них:

    • Singleton ��: Обеспечивает создание только одного экземпляра класса и предоставление глобальной точки доступа к этому экземпляру.
    • Фабричный метод ��: Определяет интерфейс для создания объектов, позволяя подклассам выбирать, какой класс инстанциировать.
    • Абстрактная фабрика ��: Предоставляет интерфейс для создания семейств взаимосвязанных объектов без указания их конкретных классов.
    • Прототип ��: Позволяет создавать новые объекты путем копирования существующих объектов (прототипов), вместо создания новых объектов с нуля.

    2. Структурные паттерны

    Структурные паттерны определяют отношения между классами и объектами, создавая более сложные структуры. Вот некоторые из них:

    • Адаптер ��: Позволяет объектам с несовместимыми интерфейсами работать вместе.
    • Мост ��: Разделяет абстракцию и реализацию, так что они могут развиваться независимо друг от друга.
    • Компоновщик ��: Объединяет объекты в древовидные структуры для представления иерархии частей-целого.
    • Декоратор ��: Добавляет новые функции к существующему объекту без изменения его структуры.

    3. Поведенческие паттерны

    Поведенческие паттерны определяют обязанности и взаимодействие между объектами. Вот некоторые из них:

    • Цепочка обязанностей ⛓️: Позволяет передавать запросы по цепочке обработчиков, пока один из них не обработает запрос.
    • Команда ��: Инкапсулирует запрос в виде объекта, что позволяет параметризовать клиентов с различными запросами.
    • Итератор ��: Предоставляет способ последовательного доступа к элементам объекта-агрегата без раскрытия его внутренней структуры.
    • Наблюдатель ��: Определяет отношение «один-ко-многим» между объектами, так что при изменении состояния одного объекта автоматически уведомляются все зависимые объекты.

    Java-разработчик: новая работа через 11 месяцев
    Получится, даже если у вас нет опыта в IT

    Заключение

    Это лишь краткий обзор паттернов проектирования, доступных в Java. Использование этих паттернов может помочь вам создавать более гибкие, модульные и повторно используемые системы. Чтобы освоить их, практика и опыт являются ключевыми факторами. Удачи в изучении паттернов проектирования!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *