Влияние на АОП с атрибутами через IoC; Кодовый запах или элегантный? - PullRequest
8 голосов
/ 10 февраля 2010

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

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

public interface IFoo {
    [CacheDuration(20)] // cache for 20 minutes
    string[] DoSomethingReusable();

    SomeType DoSomethingNonReusable(int key); // not cached
}

Идея заключается в том, что, добавляя пользовательское «соглашение» к сканированию StructureMap (довольно просто), можно обнаружить, что один или несколько методов оформлены для кэширования, и автоматически внедрить сгенерированный декоратор кэширования в это конвейер типа (генерирующий ключ кеша из имени интерфейса / метода и значений параметров).

С положительной стороны это делает добавление кеширования очень безболезненным - просто немного украсьте интерфейс; но это запах кода? И / или я дублирую что-то, что уже решено?

Ответы [ 7 ]

7 голосов
/ 10 февраля 2010

Атрибуты в порядке, если вы знаете два основных фактора:

  • изначально децентрализованная структура, вместо того, чтобы в одном месте ваши метаданные были разбросаны по каждому компоненту, к которому она прикасается

  • Жесткая постоянная структура компилятора. Если вы вдруг решите, что продолжительность вашего кэша должна быть 10, а не 20, вам придется перекомпилировать весь ваш код. Вы можете перенаправить атрибуты на такие вещи, как config, но это работает вокруг атрибутов, и на этом этапе вы должны действительно пересмотреть, было ли их использование в первую очередь лучшей идеей.

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

5 голосов
/ 10 февраля 2010

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

Мы делаем то же самое в Safewhere, но вместо этого используем регистрацию на основе конвенции. Мы также используем Castle Windsor, поэтому я не знаю, возможно ли это с StructureMap, но мы просто сканируем соответствующие сборки по имени Caching*Repository и регистрируем их как декораторы для реальных хранилищ. У нас также есть основанный на соглашении модульный тест, который проверяет наличие всех необходимых кэширующих репозиториев.

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

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

2 голосов
/ 10 февраля 2010

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

Я также думаю, что ваш код несет ответственность за решение, следует ли что-то кэшировать или нет, а не класса / интерфейса.

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

1 голос
/ 16 мая 2011

Я немного опоздал на вечеринку по этому вопросу, но недавно я думал об этой проблеме, и в целом использование атрибутов для кэширования - это запах кода .

Вот несколько причин, почему:

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

  2. Кэширование по атрибуту опасно, поскольку, хотя процесс добавления элементов в кэш обычно одинаков (т.е. cache.Add (ключ, значение)), процесс определения ключа и элемента, который нужно вставить не всегда одно и то же и обычно требует какой-то логики, которая не всегда является общей. Например, часто думают о том, чтобы сгенерировать ключ кэша, используя значения параметров, но рассмотрим сценарий, в котором используется параметр DateTime, и вызывающая сторона передает DateTime.Now ... возвращаемое значение всегда может быть одинаковым, но ключ, сгенерированный параметрами, будет другим и будет генерировать новый объект кэша для каждого вызова. Затем вы можете изменить дизайн метода, но тогда вы точно попадете в проблему, описанную в 1

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

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

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

1 голос
/ 09 ноября 2010

Я думаю, что каждый раз, когда вы используете атрибуты, необходимо учитывать связь намерения с классом. Дело в том, что вы не можете использовать эту сущность в одном месте с продолжительностью кэша 10 секунд и в другом месте с продолжительностью кэша 60 секунд. ИМХО, это всегда компромисс с атрибутами любого рода.

1 голос
/ 10 февраля 2010

Я склонен согласиться с тем, что было сказано о том, что кэширование должно быть решено вашим кодом, но я вижу, что вам нужно принять во внимание другой сценарий: «Что нужно кэшировать, весь объект?

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

Может быть, атрибут

[Cache(Duration=20, Location(...))]

1 голос
/ 10 февраля 2010

Не могу сказать, что полностью все понимаю, но для моих 2 центов это, возможно, вполне нормально; но мне просто интересно, легко ли это изменить без перекомпиляции. И, возможно, вы захотите изменить длительность этого кэша с помощью записи конфигурации, а не компиляции. Я, вероятно, храню эти данные где-нибудь, где я могу легче настроить. (Возможно, я неправильно понял ...)

...