Передача аргументов определенному подклассу через фабричный метод - PullRequest
8 голосов
/ 13 мая 2009

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

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

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

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

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

Ответы [ 7 ]

4 голосов
/ 13 мая 2009

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

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);
    }
}

Редактировать:

Если желательно иметь только один метод в классе 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.");
        }
    }
}
2 голосов
/ 13 мая 2009

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

1 голос
/ 13 мая 2009

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

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

0 голосов
/ 04 мая 2014

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

0 голосов
/ 13 мая 2009

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

Например, в вашем случае - WineFactory нужен сомелье, чтобы он мог построить соответствующий Wine -

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

0 голосов
/ 13 мая 2009

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

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

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

0 голосов
/ 13 мая 2009

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

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

...