Ответ 1
Я не думаю, что вы ничего здесь упускаете, и ограничение действительно является результатом использования ткачества времени компиляции.
Хотя я думаю, что инструменты ткачества времени компиляции имеют свое место в разработке программного обеспечения, я чувствую, что они часто чрезмерно используются. Часто я вижу, как они используются для исправления недостатков в дизайне приложения. В приложениях, которые я создаю, я применяю общие интерфейсы для определенных архитектурных концепций. Например, я определяю:
- интерфейс
ICommandHandler<TCommand>
для сервисов, которые реализуют определенный вариант использования; - интерфейс
IQueryHandler<TQuery, TResult>
для служб, которые выполняют запрос; - интерфейс
IRepository<TEntity>
как абстракция над репозиториями; - интерфейс
IValidator<TCommand>
для компонентов, которые выполняют проверку сообщений; - И так далее, и так далее.
Это позволяет мне создать единый универсальный декоратор для такой группы артефактов (например, TransactionCommandHandlerDecorator<TCommand>
который позволяет запускать каждый TransactionCommandHandlerDecorator<TCommand>
использования в своей собственной транзакции). Использование декораторов имеет много преимуществ, таких как:
- Эти универсальные декораторы полностью независимы от инструментов, поскольку нет ссылки на инструмент для создания кода или библиотеку перехвата. Аспекты PostSharp полностью зависят от PostSharp, а перехватчики всегда зависят от инфраструктуры перехвата, такой как Castle.DynamicProxy.
- Поскольку декоратор является просто нормальным компонентом, зависимости могут быть введены в конструктор, и они могут играть нормальную роль, когда вы составляете свои графы объектов с помощью Dependency Injection.
- Код декоратора очень чистый, поскольку отсутствует зависимость от какого-либо стороннего инструмента.
- Поскольку они не зависят от инструментов и допускают внедрение зависимостей, декораторы могут быть легко протестированы модульно, без необходимости возвращаться к специальным трюкам.
- Прикладной код, который требует применения сквозных задач, также может быть легко протестирован в изоляции, поскольку декораторы не включаются во время компиляции. Когда декораторы включаются во время компиляции, вы всегда вынуждены выполнять интеграционный стиль тестирования кода своего приложения или должны возвращаться к специальным приемам сборки, чтобы предотвратить их применение в проекте модульного тестирования.
- Декораторы могут быть применены динамически и условно во время выполнения, так как не происходит переплетения кода времени компиляции.
- Производительность идентична (или даже выше), чем при переплетении кода, потому что во время конструирования объекта не происходит отражения.
- Там нет необходимости отмечать ваши компоненты с атрибутами, чтобы отметить, что некоторые аспекты должны быть применены. Это освобождает код вашего приложения от каких-либо знаний о таких сквозных проблемах и значительно упрощает его замену.
Много было написано об этом виде разработки приложений; Вот несколько статей, которые я написал сам:
- Между тем... на командной стороне моей архитектуры
- Между тем... на стороне запроса моей архитектуры
- Написание высоко обслуживаемых сервисов WCF
- Глава 10 "Аспектно-ориентированное программирование с помощью дизайна" моей книги " Принципы внедрения зависимостей, практики, шаблоны" содержит очень подробное обсуждение этого типа дизайна.
ОБНОВИТЬ
Декораторы великолепны, но в AOP мне нравится концепция советов и точек соединения. Есть ли способ симулировать такую же возможность с декоратором? Я мог только думать об отражении прямо сейчас.
Точка соединения - это "четко определенное место в классе, к которому нужно присоединиться". Когда вы применяете AOP с использованием декораторов, вы будете "ограничены" для объединения точек, находящихся на границах метода. Однако, если вы придерживаетесь SRP, OCP и ISP, у вас будут очень тонкие интерфейсы (обычно одним способом). Делая это, вы заметите, что вряд ли когда-либо есть причина для того, чтобы иметь точку соединения в любом другом месте в ваших классах.
Совет - это "проблема, которая потенциально изменит входные и/или выходные данные целевого метода". При работе с декораторами и дизайном на основе сообщений (то, что я здесь рекламирую), вашему Совету необходимо изменить сообщение (или заменить полное сообщение измененными значениями) или изменить выходное значение. Вещи не сильно отличаются от ткачества кода - если вы применяете Совет, между всем кодом, к которому применяется Совет, должно быть что-то общее.