Как зарегистрировать несколько реализаций интерфейса с несколькими ключами в замке Виндзор? - PullRequest
1 голос
/ 20 октября 2011

У меня есть такой интерфейс проверки:

public interface IValidation<T> {
  bool IsValid(T item, ref AggregateException fail);
}

У меня есть импортер файлов, которому нужно несколько интерфейсов проверки

public FileImporter {
  IEnumerable<IValidation<Patient>> Validators { get; set; }

  public FileImporter(IWindsorContainer container) {
    // the ResolveAll method does not do this
    Validators = container.ResolveAll<IValidation<Patient>>("fileValidation");
  }
}

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

public PatientService {
  IEnumerable<IValidation<Patient>> Validators { get; set; }

  public PatientService(IWindsorContainer container) {
    // the ResolveAll method does not do this
    Validators = container.ResolveAll<IValidation<Patient>>("userInputValidation");
  }
}

Например, у меня есть два валидатора LastNameValidator и DateOfBirthValidator.LastNameValidator is used in both the FileImporter and the PatientService . DateOfBirthValidator is only used in the Класс PatientService`.Реализация этих двух классов ниже вопроса.

Мой вопрос заключается в том, как мне соединить эти два класса так, чтобы они использовались, как описано выше.И какой вызов метода я должен сделать, чтобы решить их?

public class LastNameValidator : IValidation<Patient> {
  public bool IsValid(Patient p, ref AggregateException fail) {
    var isValid = !string.IsNullOrWhitespace(p.LastName))
    if (!isValid)
        // update fail
    return isValid;
  }
}

public class DateOfBirthValidator : IValidation<Patient> {
  public bool IsValid(Patient p, ref AggregateException fail) {

    if (!p.DateOfBirth.HasValue) {
        // update fail, can't be empty
        return false;
    }
    if (p.DateOfBirth.Value > DateTime.Now) {
        // update fail, can't be in future
        return false;
    }
    return true;
  }
}

1 Ответ

1 голос
/ 20 октября 2011

Я бы рассмотрел Типизированный завод . Вы можете зарегистрировать свои валидаторы с именами «lastnamevalidator» и «dobvalidator». Затем создайте фабричный интерфейс для получения этих конкретных валидаторов. Вам просто нужен интерфейс - средство выполнит реализацию:

public interface IValidatorFactory
{
    IValidator GetLastNameValidator();
    IValidator GetDobValidator();
}

Теперь передайте фабрику IValidator вашему компоненту. Это также избавляет от необходимости передавать контейнер Windsor (что не очень хорошая идея, поскольку он тесно связывает ваш код с Windsor и усложняет модульное тестирование).

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

UPDATE:

До сих пор неясно, какая часть вашей системы будет определять, какие IValidators использовать, но, возможно, это сработает. Используйте маркерный интерфейс, основанный на IValidator.

public interface IFileValidator : IValidator
{
}

public interface IUserInputValidator : IValidator
{
}

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

public class FileValidator : IFileValidator
{
    public bool IsValid()
    {
        return false;
    }
}

public class DobValidator : IUserInputValidator, IFileValidator
{
    public bool IsValid()
    {
        return false;
    }
}

public class LastNameValidator : IUserInputValidator
{
    public bool IsValid()
    {
        return true;
    }
}

Измените заводской интерфейс, чтобы он возвращал только определенные типы валидаторов:

public interface IValidatorFactory
{
    IFileValidator[] GetFileValidators();
    IUserInputValidator[] GetUserInputValidators();
}

Теперь зарегистрируйте валидаторы, соответствующие их «типу». Если валидатор имеет многократное использование, обязательно добавьте определение .Forward<> для Windsor:

var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
    Component.For<IValidatorFactory>().AsFactory(),

    Component.For<IFileValidator>().ImplementedBy<FileValidator>(),
    Component.For<IUserInputValidator>().ImplementedBy<LastNameValidator>(),
    Component.For<IFileValidator>().Forward<IUserInputValidator>().ImplementedBy<DobValidator>()
    );
...