2014-12-22 2 views
1

Итак, я реализовал то, что, как мне кажется, называется инъекцией зависимостей (пожалуйста, поправьте меня, если я ошибаюсь!).Как структурировать инъекцию зависимостей в C#

У меня есть класс FooModel, который поддерживает состояние Foo. Здесь есть некоторые асинхронные методы, которые пытаются попробовать что-то. Обычно они работают, иногда они терпят неудачу на разных этапах. Я хотел бы, чтобы реализация FooModel и UpdateFoo() заставила абонентов реализовать их обработку того, что происходит в UpdateFoo(). Вот простой пример:

public class FooModel 
{ 
    private FooState fooState; 

    public async Task UpdateFooAsync(IHandler handler) 
    { 
     try 
     { 
      var newFooState = await Something(); 
      fooState = newFooState; 

      handler.ItWorked(); 
     } 
     catch 
     { 
      handler.ItDidntWork(); 
     } 
    } 
} 

public interface IHandler 
{ 
    public void ItWorked(); 
    public void ItDidntWork(); 
} 

Теперь есть несколько других моделей, которые могут потребоваться для вызова UpdateFoo(). Например, рассмотрим BarModel:

public class BarModel 
{ 
    private BarState barState; 
    private FooModel foo; 

    public Bar() 
    { 
     this.foo = ModelProvider.Foo; 
    } 

    public void DoBar() 
    { 
     foo.UpdateFoo(new Handler(this)); 
    } 

    private void Continue() {} 
    private void TryOtherThing() {} 

    public class Handler : IHandler 
    { 
     private BarModel bar; 

     public Handler(BarModel bar) 
     { 
      this.bar = bar; 
     } 

     public void ItWorked() 
     { 
      bar.Continue(); 
     } 
     public void ItDidntWork() 
     { 
      bar.TryOtherThing(); 
     } 
    } 
} 

Имейте в виду, что это простой пример. В UpdateFoo() может быть 2 - 6 "вилок". И может быть несколько разных классов, которые нужно вызвать UpdateFoo(). Я хочу заставить все эти вызывающие классы что-то делать на каждой из этих разных «вилок», поэтому я использовал интерфейс.

Однако, кажется невероятно громоздким, чтобы явно реализовать вложенный класс для каждого класса, который хочет вызвать UpdateFoo(). Тем более, что я должен передать родительский класс в качестве аргумента конструктору и т. Д. Идея вложенного класса вообще не сидит прямо со мной.

Является ли это хорошей идеей? Или это ужасно? Существуют ли более чистые рефакторинги? Я не могу сказать.

Edit: Изменены некоторые вещи в соответствии с рекомендациями Кай Brummund в

+0

Что вы делают больше похоже на Command или Strategy-Pattern для меня. Я бы рекомендовал вам посмотреть на эти два. Инъекция зависимостей больше связана с зависимостями класса при времени построения/инициализации. Вызывающие методы не должны знать внутренние зависимости вашего класса. –

+1

Другие подсказки OT: методы Async должны отражать это от их имени: UpdateFooAsync(), и вы никогда не должны использовать async void, если это возможно. Сделайте это async Task. –

+0

Существует также точка, в которой ваш код явно разбивает инъекцию зависимостей: ваш BarModel имеет зависимость от Foo, но вы получаете его через ModelProvider в конструкторе. Если вы позволите передать в modelprovider или даже сам Foo в качестве аргументов, это будет инъекция зависимостей. –

ответ

2

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

public async void UpdateFoo(Action successAction, Action failureAction) 
{ 
    if (successAction == null) 
    { 
     throw new ArgumentNullException("successAction"); 
    } 
    if (failureAction == null) 
    { 
     throw new ArgumentNullException("failureAction"); 
    } 

    try 
    { 
     var newFooState = await Something(); 
     fooState = newFooState; 

     successAction(); 
    } 
    catch 
    { 
     failureAction(); 
    } 
} 

И использовать его как это ...

public void DoBar() 
{ 
    foo.UpdateFoo(Continue, TryOtherThing); 
} 

... или это:

public void DoBar() 
{ 
    foo.UpdateFoo(() => Console.WriteLine("Epic win!"),() => Console.WriteLine("Fail.")); 
} 
+0

Часто бывает больше 2, иногда до 8 или около того. Это, наверное, слишком много, как вы думаете? – bkjvbx

+0

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

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