Шаблон спецификации - Specification pattern
В компьютерном программировании шаблон спецификации особый шаблон разработки программного обеспечения, Посредством чего бизнес правила могут быть повторно объединены путем объединения бизнес-правил вместе с использованием логической логики. Шаблон часто используется в контексте предметно-ориентированный дизайн.
Шаблон спецификации описывает бизнес-правило, которое можно комбинировать с другими бизнес-правилами. В этом шаблоне единица бизнес-логики наследует свои функции от абстрактного совокупного класса составной спецификации. В классе Composite Specification есть одна функция IsSatisfiedBy, которая возвращает логическое значение. После создания экземпляра спецификация «связывается» с другими спецификациями, что делает новые спецификации легко обслуживаемыми, но при этом легко настраиваемой бизнес-логикой. Кроме того, при создании экземпляра бизнес-логика может посредством вызова метода или инверсия контроля, изменили его состояние, чтобы он стал делегатом других классов, таких как репозиторий сохраняемости.
Примеры кода
C #
общественный интерфейс Спецификация { bool IsSatisfiedBy(объект кандидат); Спецификация И(Спецификация Другой); Спецификация И нет(Спецификация Другой); Спецификация Или же(Спецификация Другой); Спецификация Или нет(Спецификация Другой); Спецификация Нет(); } общественный Абстрактные учебный класс Композитный : Спецификация { общественный Абстрактные bool IsSatisfiedBy(объект кандидат); общественный Спецификация И(Спецификация Другой) { возвращаться новый ИСпецификация(это, Другой); } общественный Спецификация И нет(Спецификация Другой) { возвращаться новый AndNotSpecification(это, Другой); } общественный Спецификация Или же(Спецификация Другой) { возвращаться новый Или Спецификация(это, Другой); } общественный Спецификация Или нет(Спецификация Другой) { возвращаться новый OrNotSpecification(это, Другой); } общественный Спецификация Нет() { возвращаться новый NotSpecification(это); } } общественный учебный класс ИСпецификация : Композитный { частный Спецификация leftCondition; частный Спецификация rightCondition; общественный ИСпецификация(Спецификация оставили, Спецификация верно) { leftCondition = оставили; rightCondition = верно; } общественный отменять bool IsSatisfiedBy(объект кандидат) { возвращаться leftCondition.IsSatisfiedBy(кандидат) && rightCondition.IsSatisfiedBy(кандидат); } } общественный учебный класс AndNotSpecification : Композитный { частный Спецификация leftCondition; частный Спецификация rightCondition; общественный AndNotSpecification(Спецификация оставили, Спецификация верно) { leftCondition = оставили; rightCondition = верно; } общественный отменять bool IsSatisfiedBy(объект кандидат) { возвращаться leftCondition.IsSatisfiedBy(кандидат) && rightCondition.IsSatisfiedBy(кандидат) != истинный; } } общественный учебный класс Или Спецификация : Композитный { частный Спецификация leftCondition; частный Спецификация rightCondition; общественный Или Спецификация(Спецификация оставили, Спецификация верно) { leftCondition = оставили; rightCondition = верно; } общественный отменять bool IsSatisfiedBy(объект кандидат) { возвращаться leftCondition.IsSatisfiedBy(кандидат) || rightCondition.IsSatisfiedBy(кандидат); } } общественный учебный класс OrNotSpecification : Композитный { частный Спецификация leftCondition; частный Спецификация rightCondition; общественный OrNotSpecification(Спецификация оставили, Спецификация верно) { leftCondition = оставили; rightCondition = верно; } общественный отменять bool IsSatisfiedBy(объект кандидат) { возвращаться leftCondition.IsSatisfiedBy(кандидат) || rightCondition.IsSatisfiedBy(кандидат) != истинный; } } общественный учебный класс NotSpecification : Композитный { частный Спецификация Завернутый; общественный NotSpecification(Спецификация Икс) { Завернутый = Икс; } общественный отменять bool IsSatisfiedBy(объект кандидат) { возвращаться !Завернутый.IsSatisfiedBy(кандидат); } }
C # 6.0 с дженериками
общественный интерфейс Спецификация<Т> { bool IsSatisfiedBy(Т кандидат); Спецификация<Т> И(Спецификация<Т> Другой); Спецификация<Т> И нет(Спецификация<Т> Другой); Спецификация<Т> Или же(Спецификация<Т> Другой); Спецификация<Т> Или нет(Спецификация<Т> Другой); Спецификация<Т> Нет(); } общественный Абстрактные учебный класс LinqSpecification<Т> : Композитный<Т> { общественный Абстрактные Выражение<Func<Т, bool>> AsExpression(); общественный отменять bool IsSatisfiedBy(Т кандидат) => AsExpression().Компилировать()(кандидат); } общественный Абстрактные учебный класс Композитный<Т> : Спецификация<Т> { общественный Абстрактные bool IsSatisfiedBy(Т кандидат); общественный Спецификация<Т> И(Спецификация<Т> Другой) => новый ИСпецификация<Т>(это, Другой); общественный Спецификация<Т> И нет(Спецификация<Т> Другой) => новый AndNotSpecification<Т>(это, Другой); общественный Спецификация<Т> Или же(Спецификация<Т> Другой) => новый Или Спецификация<Т>(это, Другой); общественный Спецификация<Т> Или нет(Спецификация<Т> Другой) => новый OrNotSpecification<Т>(это, Другой); общественный Спецификация<Т> Нет() => новый NotSpecification<Т>(это); } общественный учебный класс ИСпецификация<Т> : Композитный<Т> { Спецификация<Т> оставили; Спецификация<Т> верно; общественный ИСпецификация(Спецификация<Т> оставили, Спецификация<Т> верно) { это.оставили = оставили; это.верно = верно; } общественный отменять bool IsSatisfiedBy(Т кандидат) => оставили.IsSatisfiedBy(кандидат) && верно.IsSatisfiedBy(кандидат); } общественный учебный класс AndNotSpecification<Т> : Композитный<Т> { Спецификация<Т> оставили; Спецификация<Т> верно; общественный AndNotSpecification(Спецификация<Т> оставили, Спецификация<Т> верно) { это.оставили = оставили; это.верно = верно; } общественный отменять bool IsSatisfiedBy(Т кандидат) => оставили.IsSatisfiedBy(кандидат) && !верно.IsSatisfiedBy(кандидат); } общественный учебный класс Или Спецификация<Т> : Композитный<Т> { Спецификация<Т> оставили; Спецификация<Т> верно; общественный Или Спецификация(Спецификация<Т> оставили, Спецификация<Т> верно) { это.оставили = оставили; это.верно = верно; } общественный отменять bool IsSatisfiedBy(Т кандидат) => оставили.IsSatisfiedBy(кандидат) || верно.IsSatisfiedBy(кандидат); } общественный учебный класс OrNotSpecification<Т> : Композитный<Т> { Спецификация<Т> оставили; Спецификация<Т> верно; общественный OrNotSpecification(Спецификация<Т> оставили, Спецификация<Т> верно) { это.оставили = оставили; это.верно = верно; } общественный отменять bool IsSatisfiedBy(Т кандидат) => оставили.IsSatisfiedBy(кандидат) || !верно.IsSatisfiedBy(кандидат); } общественный учебный класс NotSpecification<Т> : Композитный<Т> { Спецификация<Т> Другой; общественный NotSpecification(Спецификация<Т> Другой) => это.Другой = Другой; общественный отменять bool IsSatisfiedBy(Т кандидат) => !Другой.IsSatisfiedBy(кандидат); }
Python
из abc импорт абстрактный методиз классы данных импорт класс данныхиз набор текста импорт Любойучебный класс BaseSpecification: @abstractmethod def is_satisfied_by(себя, кандидат: Любой) -> bool: поднимать NotImplementedError() def и_(себя, Другой: «Базовая спецификация») -> "AndSpecification": возвращаться ИСпецификация(себя, Другой) def или же_(себя, Другой: «Базовая спецификация») -> "OrSpecification": возвращаться Или Спецификация(себя, Другой) def нет_(себя) -> "NotSpecification": возвращаться NotSpecification(себя)@dataclass(замороженный=Истинный)учебный класс ИСпецификация(BaseSpecification): первый: BaseSpecification второй: BaseSpecification def is_satisfied_by(себя, кандидат: Любой) -> bool: возвращаться себя.первый.is_satisfied_by(кандидат) и себя.второй.is_satisfied_by(кандидат)@dataclass(замороженный=Истинный)учебный класс Или Спецификация(BaseSpecification): первый: BaseSpecification второй: BaseSpecification def is_satisfied_by(себя, кандидат: Любой) -> bool: возвращаться себя.первый.is_satisfied_by(кандидат) или же себя.второй.is_satisfied_by(кандидат)@dataclass(замороженный=Истинный)учебный класс NotSpecification(BaseSpecification): предмет: BaseSpecification def is_satisfied_by(себя, кандидат: Любой) -> bool: возвращаться нет себя.предмет.is_satisfied_by(кандидат)
Пример использования
В следующем примере мы получаем счета и отправляем их в коллекторское агентство, если
- они просрочены,
- уведомления были отправлены, и
- они еще не работают с коллекторским агентством.
Этот пример предназначен для того, чтобы показать конечный результат того, как логика «сцепляется» вместе.
В этом примере использования предполагается, что ранее определенный класс OverdueSpecification выполняется, когда срок оплаты счета составляет 30 дней или старше, класс NoticeSentSpecification, который удовлетворяется, когда клиенту отправлены три уведомления, и класс InCollectionSpecification, который выполняется, когда счет-фактура уже отправлено в коллекторское агентство. Реализация этих классов здесь не важна.
Используя эти три спецификации, мы создали новую спецификацию под названием SendToCollection, которая будет удовлетворена, когда счет будет просрочен, когда уведомления будут отправлены клиенту, но еще не отправлены в коллекторское агентство.
вар OverDue = новый OverDueSpecification();вар Уведомление отправлено = новый NoticeSentSpecification();вар InCollection = новый InCollectionSpecification();// пример логической цепочки шаблона спецификациивар SendToCollection = OverDue.И(Уведомление отправлено).И(InCollection.Нет());вар InvoiceCollection = Служба.GetInvoices();для каждого (вар currentInvoice в InvoiceCollection) { если (SendToCollection.IsSatisfiedBy(currentInvoice)) { currentInvoice.SendToCollection(); }}
Критика
Шаблон спецификации можно рассматривать как программное обеспечение антипаттерн:
- Культ карго - У этого паттерна нет четко определенной цели и нет руководства, когда его применять или нет. Также см Закон инструмента.
- Эффект внутренней платформы - Функция And (), которая напрямую копирует && в C #. Также Not () и потенциально больше. Также см Изобретая квадратное колесо заново.
- Код спагетти / лазаньи - Отдельные классы для каждой части спецификации фрагментов, которые могут быть единым объектом. В приведенном выше примере OverDue - это дополнительный уровень между логикой для
SendToCollection
иOverDueSpecification
выполнение.
Большинство естественных языков программирования могут приспособить предметно-ориентированный дизайн с основными объектно-ориентированными концепциями.
Альтернативный пример без шаблона спецификации:
вар InvoiceCollection = Служба.GetInvoices();для каждого (вар выставленный счет в InvoiceCollection) выставленный счет.SendToCollectionIfNeeded();// Методы выставления счетов:общественный пустота SendToCollectionIfNeeded(){ если (ShouldSendToCollection()) SendToCollection();}частный bool ShouldSendToCollection() => currentInvoice.OverDue && currentInvoice.Уведомление отправлено && !currentInvoice.InCollection;
В этой альтернативе используются базовые концепции свойств только для получения, логики условий и функций. Ключевой альтернативой здесь являются Get-Only Properties, которые хорошо названы для поддержки предметно-ориентированного языка и позволяют продолжать использовать естественный &&
вместо оператора Specification Pattern И()
функция. Кроме того, создание хорошо названной функции SendToCollectionIfNeeded
потенциально более полезен и нагляден, чем предыдущий пример (который также может содержаться в такой функции, но не непосредственно на объекте).
Рекомендации
- Эванс, Эрик (2004). Доменно-ориентированный дизайн. Эддисон-Уэсли. п. 224.
внешняя ссылка
- Характеристики Эрик Эванс и Мартин Фаулер
- Шаблон спецификации: грунтовка Мэтт Бертер
- Шаблон спецификации: введение из четырех частей с использованием VB.Net Ричард Далтон
- Шаблон спецификации в PHP Моше Бревда
- Спецификация доктрины Happyr в PHP по Happyr
- Шаблон спецификации в Swift Саймон Страндгаард
- Шаблон спецификации в TypeScript и JavaScript Автор: Тьяго Дельгадо Пинто
- шаблон спецификации во Flash ActionScript 3 Рольф Фрейденбергер