Я знаю, что вы сказали, что хотите иметь стабильный контракт.Но преимущество , а не в предоставлении стабильного интерфейса состоит в том, что ваши зависимости могут сильно отличаться в зависимости от реализации, что уменьшит связь:
public interface IBlogRepository
{
IEnumerable<Entry> GetEntries(int pageId, int pageCount);
}
class BlogDatabase : IBlogRepository
{
public BlogDatabase(ISession session)
{
this.session = session;
}
public IEnumerable<Entry> GetEntries(int pageId, int pageCount)
{
// Not that you should implement your queries this way...
var query = session.CreateQuery("from BlogEntry");
return query.Skip(pageId * pageCount).Take(pageCount);
}
private ISession session;
}
Как вы сказали, вы также можетереализовать зависимости как свойства (или аргументы), но это жестко закодирует ваши зависимости, а не делает их специфичными для реализации.Вы будете разъединять свои конкретные реализации сессий, но вам все равно придется зависеть от сессий.
public interface IBlogRepository
{
ISession Session { get; set; }
IEnumerable<Entry> GetEntries(int pageId, int pageCount);
IEnumerable<Entry> GetEntriesWithSession(ISession session,
int pageId, int pageCount);
}
class BlogDatabase : IBlogRepository
{
public ISession Session { Get; set; }
public IEnumerable<Entry> GetEntries(int pageId, int pageCount)
{
var query = Session.CreateQuery ...
}
public IEnumerable<Entry> GetEntries(ISession session, int pageId, int pageCount)
{
var query = session.CreateQuery ...
}
}
class BlogFile : IBlogRepository
{
// ISession has to abstract a file handle. We're still okay
// ...
}
class BlogInMemory : IBlogRepository
{
// ISession abstracts nothing.
// Maybe a lock, at best, but the abstraction is still breaking down
// ...
}
Внедрение в конструктор будет работать только в том случае, если вы используете какую-то платформу Dependency Injection, которая может обрабатывать создание / предоставление зависимостей длявы.Внедрение свойств и аргументов будет работать даже без рамок.
Я считаю, что все три являются принятой практикой.По крайней мере, пара популярных фреймворков поддерживают внедрение как конструктора, так и свойства.
Это означает, что вам решать, что именно лучше всего подходит для вашего проекта.Компромисс - это график зависимостей, который легко отследить против более сильной связи.Решение, конечно же, не обязательно должно быть полностью-конструктор или все-свойство / аргумент.
Еще одна абстракция более высокого уровня, о которой следует подумать - это абстрактный класс фабрики.Это можно сделать, если вы хотите сгруппировать набор зависимостей или создать их экземпляры во время выполнения:
public interface IInstallationFactory
{
IUser CreateRegisteredUser(Guid userSid);
IPackage CreateKnownPackage(Guid id);
IInstaller CreateInstaller();
}
Различные инфраструктуры также поддерживают абстрактные фабрики.