Заводская модель: перечисления или типы? - PullRequest
6 голосов
/ 08 мая 2009

При реализации фабрики или простой фабрики, что будет противоречить использованию Type вместо Enum для указания класса для создания экземпляра?

Например

public class SimpleFactory
{
 public static ITest Create(Type type)
 {
  if (type == typeof(ConcreteTest1))
   return new ConcreteTest1();
  if (type == typeof(ConcreteTest2))
   return new ConcreteTest2();

  throw new Exception("Invalid type");
 }
}

Ответы [ 6 ]

15 голосов
/ 08 мая 2009

Использование enum является более ограничительным, что означает, что менее вероятно, что пользователь попытается использовать вашу фабрику с неподдерживаемым типом.

Я считаю, что хорошо делать все возможное при определении API для предотвращения использования шаблонов, которые будут вызывать исключения. Разрешение «Тип» в этом случае открывает миллионы способов вызова вашей функции, что приведет к:

throw new Exception("Invalid type");

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

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

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

Я бы создал фабрику для каждой иерархии классов. Например:

public abstract class Vehicle {}
public class Car : Vehicle {}
public class Truck : Vehicle {}

public class VehicleFactory
{
    public Vehicle CreateVehicle<T>() where T : Vehicle
    {
        // Get type of T and delegate creation to private methods
    }
}
2 голосов
/ 08 мая 2009

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

Я приведу пример в c # с использованием обобщений.

public class SimpleFactory
{
 public static ITest Create<T>()
    where T: ITest, new()
 {
    return new T();
 }
}

Тогда вы реализуете IConcreteTest как с ConcreteTest1, так и с ConcreteTest2, и вы можете использовать свою фабрику следующим образом:

ConcreteTest1 test1 = SimpleFactory.Create<ConcreteTest1>();
2 голосов
/ 08 мая 2009

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

ИМХО, лучший подход - использовать наследование, один конкретный фабричный класс для каждого конкретного типа.

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

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

Использование информации о типе, извлеченной из производного типа, все еще требует, чтобы вызывающий объект имел некоторые глубокие знания о том, какой тип он хочет создать, что затрудняет его обновление и поддержку. Подставляя тип Enum (или string, int и т. Д.), Вы можете обновить фабрику, не обновляя вызывающий код, чтобы знать о новых производных типах.

Полагаю, можно утверждать, что имя типа может быть прочитано как строка из файла конфигурации, базы данных и т. Д., А информация о типе определена с использованием Reflections (в .NET) или RTTI (в C ++), но я думаю, что это лучший вариант для простого использования строки типа в качестве идентификатора, поскольку она будет эффективно служить той же цели.

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

Если вы хотите создать по типу, вы можете просто использовать Activator.CreateInstance(Type t). Оберните его в шаблонный метод, чтобы ограничить его вашим интерфейсом, что-то вроде Create<T> where T:ITest.

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