2009-03-05 4 views
7

Одним из способов правильной инъекции зависимостей является разделение создания объектов с бизнес-логикой. Как правило, это предполагает использование Factory для создания объекта.Можно ли передавать параметры на заводский метод?

Вплоть до этого момента, я никогда серьезно не рассматривал возможность использования завода, поэтому я прошу прощения, если этот вопрос кажется немного упрощенным:

Во всех примерах Factory Pattern, который я перебежать, я всегда см. очень простые примеры, которые не имеют параметризации. Например, здесь фабрика украдена у Misko Hevery's отличная статья How To Think About the "new" Operator.

 
class ApplicationBuilder { 
    House build() { 
    return new House(new Kitchen(
       new Sink(), 
       new Dishwasher(), 
       new Refrigerator()) 
      ); 
    } 
} 

Однако, что произойдет, если я хочу, чтобы каждый дом, который я построил, имел имя? Я все еще использую шаблон Factory, если я переписал этот код следующим образом?

 
class ApplicationBuilder { 
    House build(const std::string & house_name) { 
    return new House(house_name, 
         new Kitchen(new Sink(), 
            new Dishwasher(), 
            new Refrigerator()) 
        ); 
    } 
} 

Обратите внимание, что мой метод Factory вызов изменился от этого:

 
ApplicationBuilder builder; 
House * my_house = builder.build();

Для этого:

 
ApplicationBuilder builder; 
House * my_house = builder.build("Michaels-Treehouse");

Кстати: Я думаю, что концепция разделения объекта инстанцировании от бизнес-логики отлично, я просто пытаюсь понять, как я могу применить его к моей собственной ситуации. Меня смущает то, что все примеры, которые я видел в шаблоне Factory, никогда не передают никакие параметры в функцию build().

Чтобы быть ясным: я не знаю названия дома до момента, прежде чем мне понадобится его создать.

+0

Я часто видел, что заводы принимают параметры, как вы показали. В этом нет ничего плохого. Или с точки зрения вашего вопроса. Это нормально. – grieve

ответ

8

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

Однако есть хорошая причина, по которой многие учебникам или небольшие статьи избегают фабрики, пересылать параметры для построенных объектов: Это практически невозможно передать произвольное количество аргументов (даже для здравомыслящего предела, как 6 аргументов). Каждый параметр, который вы пересылаете, должен приниматься как const T& и T&, если вы хотите сделать его общим.

Для более сложных примеров вам потребуется экспоненциально растущий набор перегрузок (для каждого параметра, константы и неконной версии) и perfect forwarding вообще не возможно (так что временные файлы пересылаются, например, как временные) , Для следующего стандарта C++, что проблема решена:

class ApplicationBuilder { 
    template<typename... T> 
    House *build(T&&... t) { 
    return new House(std::forward<T>(t)..., 
         new Kitchen(new Sink(), 
            new Dishwasher(), 
            new Refrigerator()) 
        ); 
    } 
}; 

Таким образом, вы можете позвонить

builder.build("Hello", 13); 

И вернется

new House("Hello", 13, new Kitchen(new Sink(... 

Читайте статью я связан выше.

+0

Хорошая ссылка на ссылки rvalue! Вероятно, это выходит за рамки вопроса, но это одна из самых ясных статей, которые я прочитал по этому вопросу. –

5

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

+0

Описывая, какой объект вы хотите (в параметрах), это может позволить фабрике вернуть совершенно разные объекты (путем возврата базового класса или интерфейса). – Aardvark

1

Я согласен с Benoit. Подумайте о фабрике для создания чего-то вроде sql-соединений, хотя в таком случае необходимо будет передать информацию о подключении к заводу. Завод будет использовать эту информацию для использования правильного протокола сервера и так далее.

4

Идея фабрики заключается в том, что она дает вам экземпляр класса/интерфейса, поэтому нет ничего плохого в передаче параметров. Если бы это было, было бы неплохо передать параметры и новому().

5

Не только допустимо, но это общий для передачи параметров заводскому методу. Выезд some examples. Обычно параметр - это тип, указывающий фабрике, что делать, но нет причин, по которым вы не можете добавить другую информацию, необходимую для построения объекта. Я думаю, что вы делаете хорошо.

1

Несомненно, почему бы и нет!

Приятная вещь о прохождении параметров заключается в том, что он позволяет скрыть реализацию конкретного объекта. Например, в отправленном вами коде передаются параметры конструктору. Однако вы можете изменить реализацию, чтобы они прошли через метод Initiailze. Передавая параметры фабричному методу, вы скрываете характер построения и инициализации объекта от вызывающего.

1

Посмотрите на Loki :: Factory, но реализация также очень подходит для Boost. Некоторые примеры кода я регулярно использовать в различных вариантах:

ЬурейеЕ Loki :: SingletonHolder < Loki :: Factory < компонентов, станд :: строка, Loki :: TypeList < Const DataCollection &, Loki :: TypeList < игры *, Локи :: NullType>>>> ComponentFactory;

Это может показаться немного странным с первого взгляда, однако позвольте мне объяснить этого зверя и насколько он силен. В основном мы создаем singleton, который содержит завод, большинство параметров для singleton, Component - наш продукт, std :: string - это наш тип идентификатора создания, после чего следует список типов параметров, необходимых для создания компонентов (это можно определить, используя макрос, а также для менее подробного синтаксиса). После этой строки вы можете просто:

ComponentFactory :: Instance(). CreateObject ("someStringAssociatedWithConcreteType", anDataCollection, aGamePointer);

Чтобы создать объекты, зарегистрировать их, просто используйте ComponentFactory :: Instance(). Register() ;. Есть замечательная глава о деталях в книге Modern C++ Design.