Термінологія запитання насправді не відповідає прикладу коду. Це Ambient Context
шаблон, що використовується для того, щоб якомога простіше перехопити залежність від будь-якого класу в будь-якому модулі, не забруднюючи кожен клас приймати інтерфейс залежності, але все ж зберігаючи ідею інверсії управління. Такі залежності, як правило, присвячені реєстрації, безпеці, керуванню сеансом, транзакціям, кешування, аудиту, таким чином, для будь-якої наскрізної проблеми в цій програмі. Це як - то дратує додати ILogging
, ISecurity
, ITimeProvider
конструкторам і більшу частину часу не всі класи потрібно в одне і теж час, тому я розумію вашу потребу.
Що робити, якщо термін служби ISession
екземпляра відрізняється від тривалості ILogger
? Можливо, екземпляр ISession повинен бути створений на кожен запит та ILogger один раз. Тому наявність усіх цих залежностей, якими керує один об'єкт, який не є самим контейнером, не виглядає правильним вибором через всі ці проблеми з управлінням життям та локалізацією та інші, описані в цій темі.
IAmbientContext
У цьому питанні не вирішує проблеми не забруднюючи кожен конструктор. Ви все одно повинні використовувати його в підписі конструктора, звичайно, один раз лише цього разу.
Таким чином, найпростіший спосіб НЕ використовувати конструкторський нагнітання чи будь-який інший механізм впорскування для боротьби з наскрізними залежностями, а використовуючи статичний виклик . Насправді ми часто бачимо цю закономірність, реалізовану самими рамками. Перевірте Thread.CurrentPrincipal, що є статичним властивістю, яке повертає реалізацію IPrincipal
інтерфейсу. Він також встановлений, щоб ви могли змінити реалізацію, якщо вам це подобається, таким чином, ви не зв'язані з нею.
MyCore
виглядає зараз щось на кшталт
public class MyCoreClass
{
public void BusinessFeature(string data)
{
LoggerContext.Current.Log(data);
_repository.SaveProcessedData();
SessionContext.Current.SetData(data);
...etc
}
}
Ця модель та можливі реалізації були детально описані Марком Семаном у цій статті . Можуть бути реалізації, які покладаються на сам контейнер IoC, який ви використовуєте.
Ви хочете , щоб уникнути AmbientContext.Current.Logger
, AmbientContext.Current.Session
з тих же причин , як описано вище.
Але у вас є інші варіанти вирішення цієї проблеми: використовуйте декоратори, динамічне перехоплення, якщо ваш контейнер має таку можливість або AOP. Контекст навколишнього середовища повинен бути останнім заходом через те, що його клієнти приховують через нього свої залежності. Я б все-таки використовував Ambient Context, якщо інтерфейс він насправді імітує мій імпульс використовувати статичну залежність на зразок DateTime.Now
або, ConfigurationManager.AppSettings
і ця потреба виникає досить часто. Зрештою, введення конструктора може бути не такою поганою ідеєю, щоб отримати ці всюдисущі залежності.
IService
використовується для спілкування з іншими службами?" ЯкщоIService
це нечітка залежність від інших служб, то це звучить як локатор сервісу і не має існувати. Ваш клас повинен залежати від інтерфейсів, які чітко описують, що з ними буде робити їх споживач. Жоден клас ніколи не потребує послуги, щоб забезпечити доступ до послуги. Класу потрібна залежність, яка робить щось конкретне, що потрібно класу.