Какой тип зависимости вводить? - PullRequest
2 голосов
/ 04 ноября 2010

У меня есть спецификация, которая проверяет коды. Это выглядит следующим образом:

public ClassificationSpecification : ISpecification<Classification> {
    HashSet<string> codes;

    // constructor elided

    public IsSatisfiedBy(Classification classification) {
        return codes.Contains(classification.Code);
    }
}

Действительные коды появляются из таблицы Classification в базе данных. У меня вопрос, какой конструктор для внедрения зависимостей лучше?

public CodeSpecification(IEnumerable<string> codes) {
    this.codes = new HashSet<string>(codes);
}

или

public CodeSpecification(IRepository<Classification> repository) {
    this.codes = new HashSet<string>(repository.Select(x => x.Code));
}

И главный вопрос: почему?

Ответы [ 2 ]

1 голос
/ 05 ноября 2010

Ваш второй конструктор выполняет реальную работу (через репозиторий), и это плохая идея.См. http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/

Вам необходимо решить, допустимо ли загружать все значения (передать значения, которые вам нужны, в конструктор), или вы хотите просматривать их при каждом вызове (передать в хранилище вконструктор и хранить его).

1 голос
/ 04 ноября 2010

Я бы использовал этот конструктор:

private readonly IRepository<Classification> _repository;

public CodeSpecification(IRepository<Classification> repository)
{
    _repository = repository;
}

Затем найдите действительные коды, когда ваш класс действительно вызывается:

public bool IsSatisfiedBy(Classification classification)
{
    var _repository.Any(x => x.Code == classification.Code);
}

Это гарантирует, что никакая реальная работа не будет выполнена до тех пор, пока она не потребуется, отделяя инициализацию вашего приложения от времени выполнения. Это также гарантирует, что вы всегда работаете со свежими данными в IsSatisfiedBy; кэширование значений в конструкторе вводит период времени, когда коды в хранилище могут измениться.

Если количество кодов велико, а хранилище не выполнит Any эффективно, вы все равно можете захотеть реализовать кэширование. Рекомендуется следовать тому же совету и не кэшировать до первого вызова IsSatisfiedBy:

private readonly HashSet<string> _codes;
private readonly object _codesSync = new object();

public bool IsSatisfiedBy(Classification classification)
{
    if(_codes == null)
    {
        lock(_codesSync)
        {
            if(_codes == null)
            {
                _codes = new HashSet<string>(_repository.Select(x => x.Code));
            }
        }
    }

    return _codes.Contains(classification.Code);
}

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

...