Уместно ли использовать внедрение свойств в базовом классе, когда зависимость требуется только в базовом классе?

Пример:

public abstract class BaseControler : Controller
{
    public IUnitOfWork UnitOfWork { get; set; }
}

public class HomeController : BaseControler
{
    readonly IUserRepository _userRepository;

    // :-)
    public HomeController(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }
}

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

Но что делать, если зависимость нужна только вашему базовому классу?

Когда вы будете использовать внедрение конструктора, вы, по моему мнению, загрязните все производные классы.

public abstract class BaseControler : Controller
{
    readonly IUnitOfWork _unitOfWork;

    public BaseControler(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
}

public class HomeController : BaseControler
{
    readonly IUserRepository _userRepository;

    // :-(
    public HomeController(IUserRepository userRepository, 
       IUnitOfWork unitOfWork) : base(unitOfWork)
    {
        _userRepository = userRepository;
    }
}

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


person Rookian    schedule 04.05.2012    source источник


Ответы (2)


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

Если базовому классу требуется эта зависимость для правильного функционирования, поскольку производный класс является производным от этого базового класса, он также неявно требует эту зависимость. Так что второй пример правильный. Вы не должны использовать внедрение свойств для чего-то, что является обязательной зависимостью.

person Darin Dimitrov    schedule 04.05.2012
comment
Я понимаю вашу точку зрения, но проблема, которую я получу, - это множество параметров конструктора. Дело в том, что производные классы не разговаривают напрямую с зависимостью, а не с базовым классом. Поэтому я бы различал прямые вызовы зависимости и косвенные вызовы зависимости. - person Rookian; 04.05.2012
comment
@Rookian, если вы попадаете в ситуацию, когда у вас есть несколько параметров конструктора, вы можете подумать о создании службы, которая будет агрегировать эти зависимости, а затем внедрять только службу в конструктор. - person Darin Dimitrov; 04.05.2012
comment
+1 Предпочтение композиции наследованию. Если возникает проблема со слишком большим количеством параметров конструктора, вините в этом свою стратегию наследования, а не внедрение конструктора. - person Mark Seemann; 04.05.2012
comment
@Rookian, посмотри мой ответ - производный класс говорит о зависимости, потому что он также является базовым классом. Вы только что переместили всю дублированную логику (которая использует зависимость) в базовый класс. - person Sergey Berezovskiy; 04.05.2012

На самом деле ваш производный класс является базовым классом. Где-то нет какого-то другого объекта. Когда вы передаете что-то базовому конструктору, вы фактически инициализируете тот же объект. И это показывает клиентам, от чего зависит ваш экземпляр:

public HomeController(IUserRepository userRepository, IUnitOfWork unitOfWork)

Существует ОДИН экземпляр, который зависит от двух вещей: репозитория пользователя и единицы работы. Вызов конструктора базового класса просто удаляет дублирование инициализации из ваших производных классов.

person Sergey Berezovskiy    schedule 04.05.2012