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

Паттерны проектирования сгруппированы в три категории: творческие, структурные и поведенческие. В этой статье я хотел бы сосредоточиться на одном из поведенческих паттернов, паттерне стратегии (он же политика), и на том, какую пользу мы получаем от него в интерфейсе ABP Framework. Я надеюсь, что эта статья поможет вам понять и использовать как шаблон, так и функции ABP более эффективно, чем когда-либо.

Что такое паттерн стратегии?

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

Итак, давайте посмотрим, как бы выглядели Мстители, если бы они были представлены классом:

Хотя сначала это выглядит нормально, у этого класса есть следующие недостатки:

  • Трудно recruit новый Hero на fight с другим Avengers, потому что вам нужно будет добавить еще один случай (и, вероятно, новый тип атаки) для нового героя.
  • Также сложно изменить или удалить существующий Hero. Подумайте о том, чтобы изменить атаку Тора с метания его молота, Мьёльнира, на призыв удара грома.
  • Каждая отдельная атака здесь представляет собой однострочник, но подумайте, насколько трудно было бы читать и поддерживать Avengers, если бы они были длиннее и сложнее.
  • Avengers должен обеспечить атаку для всех героев, хотя некоторые из них могут не быть в настоящее время в ensemble. Это не поколебать деревья и может привести к нерациональной трате ресурсов.

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

Итак, давайте проведем рефакторинг Avengers и посмотрим, как это выглядит при применении шаблона стратегии:

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

Давайте проверим организацию нового кода:

  • Абстрактный класс Hero предоставляет нам стратегию, контракт, который гарантирует, что алгоритм будет реализован каждым героем. Мы могли бы использовать интерфейс, но абстрактный класс здесь полезен.
  • Нам нужны конкретные стратегии, реализующие алгоритм. В данном случае это подклассы. Герои будут экземплярами этих подклассов, и все они будут иметь отдельный attack.
  • Контекст будет ссылаться на метод, гарантированный контрактом, когда вызывается fight.

Преимущества паттерна стратегии

Мы получили некоторые преимущества, реализовав описанный выше шаблон стратегии:

  1. Заявление switch пропало. Нам больше не нужно проверять условие, чтобы определить, что делать дальше.
  2. Теперь это намного проще понять и поддерживать Avengers.
  3. Кроме того, тестировать Avengers легче, чем это было раньше.
  4. Avengers может recruit любой новый Hero (Человек-паук, Человек-муравей, Алая ведьма, Сокол и т. Д.), И их attack будет просто работать. Следовательно, всегда можно ввести другую конкретную стратегию, и функциональность будет намного более расширяемой.
  5. Avengers теперь может переключаться между доступными стратегиями во время выполнения. Другими словами, теперь он может заменить UnarmedHero на ShootingHero. Подумайте о Черной вдове, которая может быть и тем, и другим.
  6. Если конкретная стратегия, подкласс Hero, не используется, она может быть изменена.

Недостатки паттерна стратегии

Есть лишь несколько недостатков, которые могут быть связаны с шаблоном стратегии:

  1. Клиент (потребитель Avengers, Ник Фурри?) Должен знать о доступных стратегиях, чтобы recruit выбрать правильную.
  2. Могут быть некоторые мирные Hero, которые не будут attack вообще, но все же должны реализовать метод noop, просто чтобы согласоваться с контрактом. Подумайте о Брюсе Бэннере (не о Халке), который может внести свой вклад в Avengers своей наукой и не участвовать в fight.
  3. Увеличивается количество генерируемых объектов. В некоторых крайних случаях это может вызвать накладные расходы. Есть еще один шаблон проектирования, шаблон нахлыста, который можно использовать для снижения этих накладных расходов.
  4. Бывают случаи, когда параметры передаются в методы, определенные стратегией. Не все стратегии используют все параметры, но их все равно нужно сгенерировать и передать.

Как ABP извлекает выгоду из паттерна стратегии

Некоторые службы в пакетах ABP Angular прибегают к шаблону стратегии, и мы планируем реорганизовать больше существующих в этом шаблоне. Давайте посмотрим, как используется DomInsertionService:

Примечательно, что у нас есть метод insertContent, и мы передаем контент, который будет вставлен в него, с помощью предопределенной стратегии контента, CONTENT_STRATEGY.AppendScriptToBody. Давайте проверим контентную стратегию:

Что ж, очевидно, ContentStrategy определяет контракт, который использует две другие стратегии: DomStrategy и ContentSecurityStrategy. Мы не собираемся копать глубже и исследовать эти стратегии, но главный вывод здесь заключается в том, что ABP использует набор стратегий для построения сложных.

Другая важная информация здесь заключается в том, что, хотя есть некоторые предопределенные стратегии, экспортируемые как константы (CONTENT_STRATEGY), используя суперклассы и / или создавая различные композиции, вы всегда можете разработать новые стратегии.

Давайте подробнее рассмотрим класс DomInsertionService:

Вызывается insertElement метод ContentStrategy, и это почти все. Алгоритм вставки делегируется стратегии. В результате здесь особо нечего читать и поддерживать, но сервис способен выполнять практически любую вставку DOM, которая может нам когда-либо понадобиться.

Заключение

Шаблон стратегии - это проверенный и многократно используемый способ сделать ваш код более гибким и расширяемым. Это также обычно приводит к созданию более читаемой, тестируемой и поддерживаемой кодовой базы. Сервисы ABP Angular, такие как LazyLoadService, ContentProjectionService и DomInsertionService, уже используют этот шаблон, и мы надеемся предоставить больше таких сервисов в ближайшем будущем.

Спасибо за чтение.

Эта статья изначально была опубликована в Блоге Волософт.