Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
//Yii2
Yii::createObject(Some::class);
//Laravel5
app(Some::class)
$some = new Some;
Service Locator нарушает инкапсуляцию класса, если он используется непосредственно в классе. Но даже в данном примере, что нам мешает использовать Service Locator для определения параметров вызова конструктора?
На том же PHP я избегаю зависимости моих классов от Service Locator (даже явной, через параметры), предпочитая получать в конструкторе или сеттерах конкретные инстансы классов/интерфейсов.
по-моему лучше чем захардкоженная зависимость от конкретных классов или, пускай, интерфейсов как в примере.
Но даже в данном примере, что нам мешает использовать Service Locator для определения параметров вызова конструктора?
Всегда что-то будет вызывать или сервис-локатор, или new.
тут смешной момент есть. там где про избегание зависимости с использованием ручного DI через конструктор. могу заметить в таком случае, что можно в целом не писать код избежав все эти зависимости)) тут же две проблемы решается как минимум, проблема рутины и проблема инверсии зависимостей.
Locator.Resolve<IWarehouseService>().В данном примере другой антипаттерн показан — чтобы использовать В надо дернуть/засетить/заинжектить А.
Кроме того, аргументы конструктора требуются немедленного разрешения, при создании экземпляра, а инъекция в поля может быть отложенной, если не использовать особых хитрых техник проксирования.
— можно сделать себе столько экземпляров ресурса, сколько нужноFunc<T>
Клиент не должен закладываться и на то что там каждый раз новый экземпляр тоже.
Но если в конструкторе указан параметр типа Func, то это подразумевает семантику фабрики, а не синглтона.
Func инжектили HttpContext, чтобы когда пользователю он нужен, он доставался текущий (при этом сам класс-потребитель был синглтон). Как следствие, между двумя вызовами он мог быть один, а мог быть разный.Owned, класс-потребитель не должен делать никаких предположений о жизненном цикле вброшенной в него зависимости.Скажем, мы через Func инжектили HttpContext, чтобы когда пользователю он нужен, он доставался текущий (при этом сам класс-потребитель был синглтон). Как следствие, между двумя вызовами он мог быть один, а мог быть разный.
(фабрика, кстати, тоже не обязана отдавать каждый раз новый экземпляр)
В норме, за исключением Owned, класс-потребитель не должен делать никаких предположений о жизненном цикле вброшенной в него зависимости.
А этот контекст имел изменяемое потребителем состояние?
HttpContext.Но то, что она [фабрика] возвращает, обязано вести себя так, как будто каждый вызов возвращает отдельный экземпляр.
если Func — можно повторно дергать для получения новой реализации.
Собственно Func с параметрами делает эту семантику еще более явной.
However, if you register an object asSingleInstance()and call theFunc<X, Y, B>to resolve the object more than once, you will get the same object instance every time regardless of the different parameters you pass in.
Конечно, имел, как и полагается HttpContext.
Почему же новой?
Наверное, если бы они не предполагали семантики «создай фабрику, которая возвращает синглтон», они бы запретили ее реализацию?
В результате объект-потребитель получает требования от Composition Root, чего быть не должно.
HttpContext. И если мы в одном поменяли, а другой увидел — значит, они в одном контексте, а если поменяли, а не увидел — значит, в разных. И это — правильное, ожидаемое поведение.Да потому, что если новая реализация не нужна, то можно, не вызывая повторно делегат, просто сохранить старую и пользоваться ей.
Нет, объект-потребитель всегда получает то, что хотел: текущий HttpContext.
Понимаете, объект за псевдо-фабрикой — это не обязательно сервис, это может быть контекст (а у них другое поведение), это может быть сущность (у них тоже свое поведение). Например, за «фабрикой» может быть identity map, который на каждый вариант параметра возвращает свой объект, но далее для того же варианта будет тот же объект.
А, вот оно в чем дело. Но тогда лучше не Func, а IObservable или IChangeable какой-нибудь — здесь, в отличие от делегата, и семантика доступа именно к текущему контексту понятна, и момент смены контекста наблюдаем.
Это я с самого начала говорил: за Func может стоять что угодно, но обязанное обеспечить семантику фабрики.
А мне не надо видеть момент смены, мне достаточно получить текущий.
Для контекстов нет семантики фабрики. Даже для доставания объектов из реестра нет семантики фабрики.
пока контекст не переключится
public interface IChangeable<T>
{
T Value { get; }
IObservable<T> Changed { get; }
}
То есть наименование типа объекта должно говорить что это
Так Func и есть наименование типа, которое ясно и четко говорит что это фабрика (семантически).
В вашей трактовке помимо Func надо смотреть еще и на тип-параметр, что усложняет и реализацию, и использование.
Вдобавок это противоречит самому понятию generic, так как ваш Func имеет разную семантику для разных типов-параметров.
если Func — можно повторно дергать для получения новой реализациинепонятно откуда взялось. На основании чего вы вкладываете в делегат семантику отдачи каждый раз нового объекта мне не понятно.
Func не закладывает такой семантики.
Равно как и Lazy не закладывает семантики singleton, на самом деле.
То есть он не должен вообще думать о внутреннем состоянии сервиса, который ему сгенерировала фабрика. Все о чем он должен думать — это что сервис выполняет обещанные контрактом операции.
Без такой семантики Func просто не нужен по построению.
Я не про внутреннее состояние, а вовсе даже про внешнее. Когда интерфейс имеет изменяемое состояние, то разница между возвратом нового и старого экземпляров при каждом вызове Func имеет значение и от этого никуда не деться. В примере с http-контекстом, если сделать два вызова делегата и начать менять состояние обоих полученных контекстов, разница между семантикой синглтона и фабрики всплывет на первом же юнит-тесте.
Func<T,bool> и Func<T,string> могут иметь разную семантику? Более того, что тот же Func<T,bool> в Where и CheckBoxFor имеет разную семантику?Да, вы можете и обойтись и без этого, но с зависимостями, чья семантика однозначно определяется типом, работать ИМХО проще.
Семантика в первую очередь определяется типом самой зависимости
Service Locator нарушает инкапсуляцию