Внедрение зависимостей и создание объектов времени выполнения - PullRequest
4 голосов
/ 05 марта 2009

Я пытался следовать принципам внедрения зависимостей, но после прочтения этой статьи я знаю, что делаю что-то не так.

Вот моя ситуация: мое приложение получает разные типы физической почты. Вся входящая почта проходит через мой MailFunnel объект.

Во время работы MailFunnel получает различные типы сообщений извне: Box, Postcard и Magazine.

Каждый тип почты должен обрабатываться по-разному. Например, если приходит ящик, мне может понадобиться записать вес перед его доставкой. Следовательно, у меня есть BoxHandler, PostcardHandler и MagazineHandler объекты.

Каждый раз, когда в мое MailFunnel приходит новое сообщение, я создаю новый соответствующий MailHandler объект.

Например:

class MailFunnel
{
  void NewMailArrived( Mail mail )
  {
    switch (mail.type)
    {
      case BOX:
        BoxHandler * bob = new BoxHandler(shreddingPolicy, maxWeightPolicy);
        bob->get_to_work();
        break;

      case POSTCARD:
        PostcardHandler * frank = new PostcardHandler(coolPicturePolicy);
        frank->get_to_work();
        break;

      case MAGAZINE:
        MagazineHandler * nancy = new MagazineHandler(censorPolicy);
        nancy->get_to_work();
        break;
    }
  }

  private:
    MaxWeightPolcy & maxWeightPolicy;
    ShreddingPolicy & shreddingPolicy;
    CoolPicturePolicy & coolPicturePolicy;
    CensorPolicy & censorPolicy;
}

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

Кроме того, в моем MailFunnel объекте есть все эти ссылки на политики, которые MailFunnel действительно не нужны. Единственная причина, по которой у MailFunnel есть эти объекты, - передать их конструкторам MailHandler. Опять же, это еще одна вещь, которую я хочу избежать .

Все рекомендации приветствуются. Спасибо!

Ответы [ 4 ]

8 голосов
/ 05 марта 2009

Для меня это больше похоже на фабрику. Переместите вызов метода get_to_work () из вызова и верните обработчик. Шаблон работает очень хорошо для фабрики.

class MailHandlerFactory
{
  IMailHandler*  GetHandler( Mail mail )
  {
    switch (mail.type)
    {
      case BOX:
        return new BoxHandler(shreddingPolicy, maxWeightPolicy);
        break;

      case POSTCARD:
        return new PostcardHandler(coolPicturePolicy);
        break;

      case MAGAZINE:
        return new MagazineHandler(censorPolicy);
        break;
    }
  }

  private:
    MaxWeightPolcy & maxWeightPolicy;
    ShreddingPolicy & shreddingPolicy;
    CoolPicturePolicy & coolPicturePolicy;
    CensorPolicy & censorPolicy;
}

class MailFunnel
{
    MailHandlerFactory* handlerFactory;

    MailFunnel( MailHandlerFactory* factory ) {
        handlerFactory = factory;
    }

    void NewMailArrived( Mail mail ) {
        IMailHandler handler = handlerFactory.GetHandler(mail);
        handler.get_to_work();
    }
}
2 голосов
/ 05 марта 2009

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

2 голосов
/ 05 марта 2009

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

На самом деле, если у вас есть что-то вроде type, скорее всего, у вас должны быть разные типы.

В основном выполните следующие действия:

1) Сделать класс Mail абстрактным.

2) Создайте три подкласса почты, Box, PostCard и Magazine

3) Дайте каждому подклассу метод для обработки почты или централизуйте его в отдельном HandlerFactory

4) При передаче в почтовую воронку просто вызовите метод handle mail или HandlerFactory передаст письмо и вернет соответствующий обработчик. Опять же, вместо того, чтобы использовать неуклюжие операторы switch везде, используйте язык, вот для чего нужна перегрузка типов и методов.

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

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

1 голос
/ 05 марта 2009

Интересно, что вы применяете внедрение зависимостей в проект C ++; это было сделано в другом месте, быстрый поиск в Google находит проект кода Google Autumn Framework .

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...