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

#architecture

#архитектура

Вопрос:

У меня есть класс под названием MessageService. Этот класс отвечает за получение электронной почты (фактически потоки). В зависимости от темы письма он определяет, о каком потоке идет речь, и выполняет действие.

немного кода для объяснения моей проблемы может быть более простым :

 public class MessageService
{
    public void ReadEmail()
    {
      switch (subject)
         "1" :
          Myservice.action1(); break;
         "2" :
          Myservice.action2(); break;
         "qwwerty" :
          MyOtherservice.Querty(); break;
          etc...
    }
}
  

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

 public MessageService(IMyService myService,IMyOtherservice myOtherservice, ect....)
{
    Myservice=myService;
    MyOtherservice=myOtherservice;
}
  

Это было бы отлично для нескольких ссылок, но класс MessageService может обрабатывать до 20,30 или сорока различных потоков. И это сделало бы инициализацию моего класса немного тяжелой.

Есть ли какой-нибудь более приятный способ добиться этого? через какой-либо шаблон проектирования? Должен ли я заботиться о IOC (хотя мне нравится запускать мои тесты в классе после ..)?

Спасибо за вашу помощь,

Ответ №1:

Вероятно, вы захотите использовать шаблон проектирования цепочки ответственности. Создайте интерфейс, который знает, как работать с электронными письмами, и создайте отдельные классы для каждой задачи, которую вы хотите выполнить (примерно эквивалентно вашему оператору switch ( switch , кстати, это очень наивная реализация COR)). Каждый из этих классов будет использовать только тот сервис, который им требуется. Затем в MessageService возьмите список этих интерфейсов и обрабатывайте их по одному, пока один из них не укажет, что он обработал это:

 public interface IMessageReader
{
  /// <returns><c>true</c> if handled; otherwise false
  bool ReadEmail(Mail message);
}

public class QwertyMessageReader : IMessageReader
{
  public QwertyMessageReader(IMyOtherService otherService) {/*set*/}
  public bool ReadEmail(Mail message)
  {
     if(message.Subject.Equals("qwwerty"))
     {
       otherService.Querty();
       return true;
     }
     return false;
  }
}

public class MessageService
{
    public MessageService(IEnumerable<IMessageReader> readers) {/*set*/}
    public void ReadEmail()
    {
      var handled = readers.Select(reader => reader.ReadEmail(message))
                           .FirstOrDefault(result => result);
    }
}
  

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

Большинство приличных контейнеров IOC автоматически сгенерируют для вас IEnumerable<>, если вы зарегистрируете несколько одного и того же интерфейса.

Комментарии:

1. Хорошее решение, мне оно очень нравится. К сожалению, я не уверен, что мой IOC справится с этой задачей, потому что он несколько самодельный, созданный каким-то коллегой, и люди действительно неохотно обращаются к чему-то другому. Я посмотрю, что я могу сделать, и вернусь.. Спасибо вам!

Ответ №2:

Лучшим предложением было бы разбить ваш класс на более мелкие классы. Наличие 30 или 40 зависимостей в одном классе является признаком того, что он выполняет слишком много. Попробуйте разбить каждый класс на что-то, что выполняет только одну вещь, а затем вы можете начать объединять их в более крупные части функциональности. Поскольку вы используете контейнер IoC, это на самом деле не должно быть слишком сложно сделать, и ваш код будет легче тестировать. Идеальной целью было бы использовать одну или две зависимости для каждого класса, но реально, я думаю, что 4 или 5 — хорошая цель для начала.

Не зная точно, что делает ваш код, трудно предложить конкретные шаблоны проектирования.

Комментарии:

1. Я тоже так думал, но я немного растерялся, не зная, как разбить мои классы… Я дам более глубокий обзор и сообщу вам, если что-нибудь найду.. Все равно спасибо.