2009-05-13 3 views
7

Предположим, что у меня есть абстрактный класс Drink и фабричный метод, который выбирает тип напитка (Wine, Beer и т. Д.) Для создания во время выполнения.Передача аргументов определенному подклассу с помощью заводского метода

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

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

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

EDIT: Предположим, что я не могу просто создать вспомогательные объекты на заводе; они доступны только от вызывающего.

ответ

4

Я бы создал различные методы перегрузки в вашем заводском классе.

public class DrinkFactory { 

    public static Drink CreateBeer(DrinkConfig config, string hops) { 
     return new Beer(config, hops); 
    } 

    public static Drink CreateWine(DrinkConfig config, string grapes, int temperature) { 
     return new Wine(config, grapes, temperature); 
    } 
} 

Edit:

Если это желательно, чтобы только один метод в классе Factory альтернативная реализация будет:

public enum DrinksEnum { 
    Beer, 
    Wine 
} 

public class DrinkFactory { 

    public static Drink CreateDrink(DrinksEnum drinkType, DrinkConfig config) { 
     switch(drinkType) { 
      case DrinksEnum.Beer: 
       return new Beer(config); 
      case DrinksEnum.Wine: 
       return new Wine(config); 
      default: 
       throw new ApplicationException("Drink type not recognised."); 
     } 
    } 
} 
+0

Подписи в порядке. Проблема в том, как вы передаете аргументы в свой Factory :: CreateDrink() (или что-то, что оно называется). – dirkgently

+0

Если вы хотите иметь метод CreateDrink на заводе, вы можете использовать параметр перечисления, чтобы указать, какой тип напитка вам нужен. Я не считаю, что этот подход или подход выше соответствуют шаблону фабрики GoF, где объекты создаются в классе Drink (мне нужно проверить мою книгу сегодня), но я нахожу ее более прагматичной и она по-прежнему сохраняет основную выгоду централизации создания объектов для иерархических подклассов. – sipwiz

+0

После проверки моей книги шаблонов дизайна GoF я рад, что приведенный выше пример - это то, насколько близко вы используете Factory как часть шаблона дизайна абстрактной фабрики. Чтобы полностью соответствовать, должен существовать абстрактный заводский класс, который наследует DrinkFactory, но для простых случаев, подобных этому, я обычно оставляю его. Было бы достаточно легко реорганизовать DrinkFactory, если потребуется другая конкретная фабрика. – sipwiz

0

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

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

0

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

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

Если вам действительно нужно передать помощников во время выполнения из вызывающего кода, я предлагаю прочитать статью «Аргументы и результаты» (http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.50.7565), которая описывает общий шаблон для сортировки сложных аргументов. По существу, вы создали бы промежуточную коллекцию необходимых параметров и передали бы это фабрике.

2

Метод фабрики должен абстрагировать детали того, как создавать ценности. Таким образом, вы не должны передавать объекты-помощники фабричному методу, фабричный метод должен создавать вспомогательный объект, который ему нужен, и передавать его соответствующему конструктору.

0

В подобных случаях я обычно смотрю на другие решения вместо передачи в переменных.

Например, в вашем случае - WineFactory нуждающиеся в Сомелье, так что можно построить соответствующее вино -

Это отличный вариант использования для инъекций во время выполнения зависимостей. Рамка инъекций зависимостей в какой-либо форме могла бы сделать эту очень простую, понятную и справедливую работу без необходимости использования всех этих свойств.

1

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

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

0

Это выглядит как идеальный случай для шаблона Builder. Используйте шаблон Factory для создания похожих объектов и шаблон Builder для построения сложных, разнородных объектов. Попытка использовать шаблон Factory для этой проблемы приведет к созданию многих, несходных конструкторов инициализации (с разными числами/типами параметров) для разных объектов.

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

  • Нет связанных вопросов^_^