2012-07-04 2 views
8

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

здесь есть проблема:

interface IValidator 
{ 
    void Validate(object obj); 
} 

public class ValidatorA : IValidator 
{ 
    public void Validate(object obj) { } 
} 

public class ValidatorB : IValidator 
{ 
    public void Validate(object obj) { } 
} 


interface IClassA { } 
interface IClassB { } 

public class MyBaseClass 
{ 
    protected IValidator validator; 

    public void Validate() 
    { 
     validator.Validate(this); 
    } 
} 

public class ClassA : MyBaseClass, IClassA 
{ 
    //problem: validator should ValidatorA 
    public ClassA(IValidator validator) { } 
} 

public class ClassB : MyBaseClass, IClassB 
{ 
    //problem: validator should ValidatorB 
    public ClassB(IValidator validator) { } 
} 

public class OtherClass 
{ 
    public OtherClass(IClassA a, IClassB b) { } 
} 


//on Main 
var oc = container.Resolve<OtherClass>(); 

Любая идея?

EDIT

Я зарегистрировал ValidatorA и ValidatorB с Named, теперь проблемой, как Виндзорский замок может впрыснуть этот валидатор правильно к ClassA и ClassB, есть ли способ сделать это? или есть ли лучшее решение?

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

  1. Validator - это сложный объект, который когда-то должен подключаться к базе данных, поэтому я должен передать интерфейс вместо реализации конструктору для обоснования модульного тестирования.
  2. Ни в коем случае использовать другой интерфейс для любого из валидатора, потому что единственный метод, который я использовал это Validate
  3. Я думаю MyBaseClass.Validate() общий шаблон метод шаблон не так ли?
+2

Ваше описание проблемы - абстрактно. –

+2

Если ClassA требует конкретной реализации IValidator, тогда дизайн ошибочен, так как интерфейс не дает никакой полезной абстракции. –

+0

@Jacek Grogon, нет, мне нужен только метод 'Validate', на самом деле есть базовый класс ClassA и ClassB, который вызывает метод' Validate'. но я не пишу его здесь, чтобы скрыть сложность. – ktutnik

ответ

9

Не вдаваясь в детали выбранной архитектуры просто упором на конфигурации контейнера Windsor:

Если вы зарегистрировали несколько назвали реализацию для данного интерфейса (IValidator), вы можете указать, какой из них вы хотите использовать при регистрации потребительских классов (ClassA, ClassB) с использованием ServiceOverrides:

следующие поставщики конфигурации контейнера OtherClass с ClassA например с экземпляром ValidatorA и ClassB с ValidatorB:

var container = new WindsorContainer(); 

container.Register(Component.For<IClassA>().ImplementedBy<ClassA>() 
    .DependsOn(ServiceOverride.ForKey<IValidator>().Eq("ValidatorA"))); 
container.Register(Component.For<IClassB>().ImplementedBy<ClassB>() 
    .DependsOn(ServiceOverride.ForKey<IValidator>().Eq("ValidatorB"))); 

container.Register(Component.For<IValidator>().ImplementedBy<ValidatorA>() 
    .Named("ValidatorA")); 
container.Register(Component.For<IValidator>().ImplementedBy<ValidatorB>() 
    .Named("ValidatorB")); 

container.Register(Component.For<OtherClass>().ImplementedBy<OtherClass>()); 

var oc = container.Resolve<OtherClass>(); 
+0

спасибо, это то, что я хочу. дело закрыто – ktutnik

1

Похоже, что вы пытаетесь поставить жесткие пары (ClassA с ValidatorA, ClassB с ValidatorB) в качестве самостоятельных типов в общий контейнер. Это бессмысленно. Если вы должны полагаться на плотную муфту, как это, забудьте об инъекции зависимостей в этом отношении и просто перепроверьте типы.

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

MyBaseClass.Validate() выглядит как инверсия элемента управления, но не как метод шаблона.

+0

спасибо за ответ, да, класс был чуть-чуть пара, но процесс повторяется, на самом деле есть задачи в 'MyBaseClass.Validate()': 1. Получите erros из 'validator.Validate (this)', 2. Dispatch 'DataErrorEvent' 3. Измените свойство' HasError', (Thats, почему я называю его методом tempalte) все эти задачи должны выполняться с помощью assynchron. было бы плохой идеей сделать это в каждом ClassA и ClassB правильно? – ktutnik

+0

Если это так, '' Validate() '' действительно метод шаблона. Тем не менее, почему бы не поместить метод ингредиентов, скажите '' ValidateCore() '' в '' ClassA'', а не в '' ValidatorA''? Если это повторяется, тогда поставьте его в 'MyBaseClass''. Извлечение класса '' Validator' добавляет больше сложности и затрудняет ясность. –

+0

Если im not msitaken, вы подразумеваете экземпляр 'ValidatorA' внутри' ClassA' и создаете новый метод 'ValidateCore', а затем вызываете' ValidateCore' из 'MyBaseClass.Validate()' right ?. Я думаю, что я не могу этого сделать, потому что невозможно выполнить единичный тест, где 'ValidatorA' или' ValidatorB' в любом случае должны подключаться к базе данных. – ktutnik

Смежные вопросы