Введение

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

Уровень развития

Концепция шаблона проектирования впервые появилась в 1977 году в книге под названием «Язык шаблонов: города, здания, строительство», написанной Кристофером Александром. В те времена писались размышления о строительстве и городском дизайне по образцу самых красивых зданий/сооружений в мире. Спустя годы, в 1994 году, группа ученых-компьютерщиков, известная как «Банда четырех», взяла на вооружение эту идею и применила ее к разработке программного обеспечения. Это описано в книге под названием «Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения».
В этой книге описывается в общей сложности 23 шаблона проектирования, и большинство из них до сих пор применимы для большинства разработчиков в куче разных ситуаций. Итак, основная идея такова: «Шаблоны проектирования — это элегантные решения повторяющихся проблем в разработке программного обеспечения». Паттерны делятся на 3 основные группы:

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

Разработка

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

Одноэлементный шаблон

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

С точки зрения кода реализация библиотеки в системе печати довольно проста. Класс singleton обычно имеет 3 основных члена:

Статический член: содержит экземпляр одноэлементного класса;
Закрытый конструктор: предотвращает создание экземпляра класса кем-либо еще;
Статический общедоступный метод: предоставляет глобальную точку доступа к объекту.

На следующем изображении показана возможная реализация решения принтера с помощью синглтона на C#.

Шаблон наблюдателя

Наблюдатель — это поведенческий шаблон проектирования, который позволяет вам определить механизм подписки для уведомления нескольких объектов о любых событиях, происходящих с объектом, за которым они наблюдают.
Представьте, что у вас есть два типа объектов: Покупатель и Магазин. Покупатель очень заинтересован в конкретной марке товара (скажем, это новая модель iPhone), который скоро должен появиться в магазине.
Покупатель может приходить в магазин каждый день и проверять наличие товара, но пока товар все еще находится в пути, большинство этих поездок было бы бессмысленным.
С другой стороны, магазин может рассылать тонны электронных писем (которые могут считаться спамом) всем покупателям каждый раз, когда новый продукт становится доступным. Это избавило бы некоторых покупателей от бесконечных походов в магазин. Хотя в то же время это огорчило бы других покупателей, не интересующихся новинками.

Объект с интересным состоянием часто называют subject, но поскольку он также будет уведомлять другие объекты об изменениях своего состояния, мы называем его издателем. Все остальные объекты, которые хотят отслеживать изменения состояния издателя, называются подписчиками. Шаблон Observer предлагает вам добавить механизм подписки в класс издателя, чтобы отдельные объекты могли подписаться или отказаться от подписки на поток событий, поступающих от этого издателя.
Итак, в качестве примера рассмотрим покупку Tesla. Представьте, что у нас есть клиенты, которые заинтересованы в покупке Tesla с начальной ценой 100 000,00 евро, но они не очень хотят отдавать столько денег, поэтому они хотели бы получать уведомления, если цена упадет. Для решения этой проблемы мы можем использовать шаблон Observer.
Мы создали 2 интерфейса для определения методов, которые должны реализовывать наши классы: ISubject и IObserver.

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

Затем мы создали класс TeslaClient, который имеет имя и wantedPrice и реализует метод Update из IObserver, который сейчас пишет в консоли, что цена Tesla ниже/равна wantedPrice.

Ниже приведен наш основной метод: мы инициализируем список клиентов, заинтересованных в Tesla, и создаем наблюдателя/издателя, который будет хранить его имена и цены. Мы прикрепили наших подписчиков к обозревателю и, наконец, мы обновили цену на Model X. Джон Доу должен быть только уведомлен клиентом, потому что 85000 ‹ 90000.

И результат:

Шаблон построителя

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

На следующем изображении показан возможный способ реализации шаблона построителя.

Шаблон фабричного метода

Фабричный метод — это шаблон проектирования, который определяет интерфейс для создания объекта, но позволяет классам, реализующим этот интерфейс, решать, экземпляр какого класса создавать. Фабричный шаблон позволяет классу отложить создание экземпляра до подклассов. Шаблон фабрики используется для замены конструкторов классов, абстрагируя процесс генерации объектов, чтобы тип создаваемого объекта можно было определить во время выполнения.
Теперь представьте, что вы создаете приложение для управления логистикой. Первая версия вашего приложения может обрабатывать перевозки только грузовиками, поэтому большая часть вашего кода находится внутри класса Truck. Через некоторое время ваше приложение становится довольно популярным. Каждый день вы получаете десятки запросов от компаний водного транспорта на включение логистики водной почты в приложение. Это потребует внесения изменений во всю кодовую базу. Более того, если позже вы решите добавить в приложение еще один вид транспорта, вам, вероятно, потребуется снова внести все эти изменения.
Паттерн Factory Method предполагает замену прямых вызовов построения объектов (используя оператор new) с вызовами специального фабричного метода. Не беспокойтесь: объекты по-прежнему создаются с помощью оператора new, но он вызывается из фабричного метода. Объекты, возвращаемые фабричным методом, часто называют продуктами.

Во-первых, мы объявляем типы транспортных средств: Truck и Ship.

Затем мы создаем интерфейс, содержащий методы, которые должны реализовывать Транспортные средства:

Сразу после этого необходимо реализовать интерфейс на наших классах Vehicles:

Затем мы создаем абстрактный класс, содержащий абстрактный метод, который будет переопределен в классах, расширяющих этот абстрактный класс:

Здесь мы расширяем класс TransportFactory и переопределяем метод, и мы возвращаем правильный класс по типу аргумента транспортного средства:

Здесь мы создаем наши методы транспортировки:

И результат таков:

Заключение

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

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

Чтобы увидеть больше статей, отметьте здесь.

The Authors: