Термінологія запитання насправді не відповідає прикладу коду. Це 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це нечітка залежність від інших служб, то це звучить як локатор сервісу і не має існувати. Ваш клас повинен залежати від інтерфейсів, які чітко описують, що з ними буде робити їх споживач. Жоден клас ніколи не потребує послуги, щоб забезпечити доступ до послуги. Класу потрібна залежність, яка робить щось конкретне, що потрібно класу.