Внедрение зависимостей в конструктор в базовом классе - PullRequest
10 голосов
/ 26 мая 2011

Я создаю базовый класс хранилища с Entity Framework, где все хранилища Entities будут наследоваться.Я хочу внедрить DatabaseContext в базовый класс, используя Dependency Injection, используя Ninject.Я думаю, что Constructor Injection - верный путь, но делая это с Constructor Injection в производном классе, я должен передать параметр конструктору в базовом классе, и я не хочу этого.Таким образом, инъекция сеттера более уместна?

Вот мой код:

public abstract class BaseRepository<TEntity> : IDisposable 
    where TEntity : class
{
    private readonly DatabaseContext _databaseContext;

    protected BaseRepository(DatabaseContext databaseContext)
    {
        this._databaseContext = databaseContext;
    }
}

Используя конструктор Injection в приведенном выше примере, в моем производном классе я должен передать объект databaseContextв базовый класс, я не люблю делать это со всем моим производным классом :

public class UsuarioRepository : BaseRepository<IUsuario>,
    IUsuarioRepository
{
    public UsuarioRepository(DatabaseContext databaseContext)
        : base(databaseContext)
    {
    }
}

Внедрение сеттера вместо инжектора конструктора - это хороший способ решить эту проблему?Каков наилучший способ?

Обновление:

Использование метода Setter Injection моего производного класса не будет иметь конструкторов:

public class UsuarioRepository : BaseRepository<IUsuario>, IUsuarioRepository
{
}

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

Решаю проблему:

Извините, я путаюсь с вопросом, но я решаю свою проблему строительства Фабрики:

public abstract class BaseRepository<TEntity> : IBaseRepository<TEntity>
   where TEntity : class
{
    private readonly ContextFactory _contextFactory = new ContextFactory();

    protected DatabaseContext CurrentContext
    {
        get
        {
            return this._contextFactory.GetCurrentContext();
        }
    }
 }

И мой производный класс будет выглядеть так:

public class UsuarioRepository : BaseRepository<IUsuario>, IUsuarioRepository
{
}

И моя фабрика вот так:

public class ContextFactory
{
    public DatabaseContext GetCurrentContext()
    {
        return new DatabaseContext();
    }
}

Ответы [ 4 ]

17 голосов
/ 26 мая 2011

Свойство Injection подразумевает, что зависимость необязательна, а Constructor Injection подразумевает, что зависимость требуется. Выберите шаблон соответственно.

В более чем 95% случаев Constructor Injection является правильным шаблоном. А что тебе не нравится?

3 голосов
/ 26 мая 2011

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

public abstract class BaseRepository<TEntity> : IDisposable 
    where TEntity : class
{
    protected BaseRepository()
    {
    }

    protected abstract DatabaseContext GetContext();
}

Теперь ваши производные классы могут выглядеть так:

public class UsuarioRepository : BaseRepository<IUsuario>,
    IUsuarioRepository
{
    private DatabaseContext _databaseContext;

    public UsuarioRepository(DatabaseContext databaseContext)
    {
        _databaseContext = databaseContext;
    }

    protected override DatabaseContext GetContext()
    {
        return _databaseContext;
    }
}

Теперь вы можете использовать конструктор без передачи параметрав базовый конструктор.Но это действительно одно и то же.

Мне, честно говоря, не нравится идея внедрения сеттера, потому что похоже, что DatabaseContext является обязательной зависимостью.Для требуемых зависимостей сделайте инъекцию конструктора.Если бы это было необязательно, то во что бы то ни стало, сделайте впрыск сеттера.

РЕДАКТИРОВАТЬ:

Из-за нашего длительного разговора в комментариях, я гораздо лучше понимаю, что вы пытаетесь достичь.

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

public class BaseRepository<TEntity> : IDisposable 
    where TEntity : class
{
    public BaseRepository(DatabaseContext context)
    {
    }
}

Теперь ваши производные классы (которыебольше не будет производным) будет выглядеть так:

public class UsuarioRepository : IUsuarioRepository
{
    public UsuarioRepository(BaseRepository<IUsario> repository)
    {
    }

    // Implement other methods here
}

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

3 голосов
/ 26 мая 2011

Я не думаю, что есть «лучший способ».

Инжектор конструктора и сеттера не совсем эквивалентен, поскольку инжекция сеттера дает вам немного больше гибкости.Вот как я выбираю между ними:

Допустим, вы создали объект A, а для работы A необходим объект B.Вопрос, который следует задать: возможно ли существование / создание экземпляра A без связанного с ним B?Это допустимое состояние для объекта A, чтобы не иметь B?Иногда для A не имеет смысла иметь нулевое значение B, тогда внедрение в конструктор является лучшим решением.Если это нормально для B, который будет назначен на A позже и не обязательно во время строительства, тогда продолжайте с установкой инъекции.Все это зависит от домена, который вы пытаетесь смоделировать, и ответы будут меняться от ситуации к ситуации.

0 голосов
/ 26 мая 2011

Все три способа 1. Contstructor, 2. Setter и 3. Interface Injection имеет свои преимущества и недостатки, которые зависят от ситуации, которую следует использовать. Если бы я был на вашем месте, я бы пошел с сеттером, хотя интерфейс также может быть хорошим выбором.

прошу вас пройти эту статью http://www.devx.com/dotnet/Article/34066

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...