Стоимость отражения при использовании фабрики
Хорошие люди из stackru,
Как всегда, я пишу фабрику, чтобы динамически создавать объекты.
Чтобы схематизировать, у меня есть четыре типа:
class CatDescriptor : PetDescriptor
class DogDescriptor : PetDescriptor
class Cat : Pet
class Dog : Pet
Я привожу два последних типа с завода. И тут возникает дилемма: нужно ли мне просто проверять типы дескрипторов с помощью оператора "is", который скрывает отражение, а затем чего-то стоить.
static Pet.Factory(PetDescriptor descriptor)
{
if (descriptor is CatDescriptor)
{
return new Cat();
}
else if (...)
{
...
}
}
Должен ли я использовать Enum "Type" в качестве атрибута, встроенного в PetDescriptor.
class PetDescriptor
{
public Type PetType;
public enum Type
{
Cat,
Dog
}
}
static Pet.Factory(PetDescriptor descriptor)
{
switch (descriptor.PetType)
{
case PetDescriptor.Type.Cat:
return new Cat();
....
}
}
Или используйте виртуальные методы:
class PetDescriptor
{
public virtual bool IsCat()
{
return false;
}
...
}
class CatDescriptor : PetDescriptor
{
public override bool IsCat()
{
return true;
}
}
static Pet.Factory(PetDescriptor descriptor)
{
if (descriptor.IsCat())
{
return new Cat();
}
else if (...)
{
...
}
}
Голоса открыты!
редактировать: вопрос касается производительности отражения, а не фабричного дизайна.
5 ответов
Так как ваш PetDescriptor
идентифицирует Pet
Я бы использовал перегрузку:
static class PetFactory
{
public static Dog CreatePet(DogDescriptor descriptor)
{
return new Dog(descriptor);
}
public static Cat CreatePet(CatDescriptor descriptor)
{
return new Cat(descriptor);
}
}
(редактировать)
Конечно, это работает только если у вас есть конкретный PetDescritor
: CatDescriptor
или же DogDescriptor
,
Если у вас нет резюме PetDescriptor
при создании я бы пошел с первым решением.
Вы также можете объявить Enum
в классе Factory, который бы указывал с бетоном Pet
ты любишь творить В Википедии есть простой пример с пиццей.
Проведение тестов на вашей фабрике лишает вас цели (вам придется обновлять свой класс для каждого нового конкретного экземпляра, который вы хотите создать).
Вы также можете:
Используйте абстрактный шаблон фабрики
(гораздо лучше) использовать инфраструктуру IoC для создания экземпляров ваших объектов для вас (я бы предложил Castle Windsor, NInject или, если вы только в магазине MS, Unity).
Ваше третье решение (с виртуальным методом) определенно отсутствует: класс PetDescriptor не должен знать обо всех его производных классах (вам придется добавлять новый метод IsXXX каждый раз, когда вы создаете класс XXXDescriptor).
Я думаю, что ваше первое решение является лучшим. Перечисление не добавляет ничего полезного, оно просто заставляет вас добавлять больше кода в классы дескрипторов.
Мой английский ужасен, поэтому я надеюсь, что правильно понял ваш вопрос.
Сколько у тебя домашних животных?
Если у вас есть 2 питомца, и вы уверены, что в будущем их количество не увеличится - не пользуйтесь никакими фабриками (не фанатично)
если там что-то около 10 домашних животных - думаю, вам нужно что-то вроде абстрактной фабрики. В этом случае - каждый дескриптор может создать своего домашнего питомца, поэтому, если у вас есть какой-либо дескриптор, вы можете создать своего домашнего питомца без дополнительной информации:
//of course u can use your own base class instead of interface.
interface IPetDescriptor
{
//here u can place some additional type information, if u need. Tags or genetic code, or maybe some story about this type
Pet CreatePet();//Maybe u need some aditional createInformation?
}
class DogDescriptor:IPetDescriptor
{
public Pet CreatePet(){ return new Dog();}
}
class CatDescriptor:IPetDescriptor
{
public Pet CreatePet(){ return new Cat();}
}
class Pet
{
public Pet static Pet.Factory(IPetDescriptor descriptor)
{
//Place for additional initialization, if u need...
//we don't care about pet type. Thats good.
return descriptor.CreatePet();
}
....
}
если есть 100 типов питомцев, гораздо лучшее решение - использовать IoC-фреймворк или написать свой собственный (например, вы можете создать тип авто-поиска):
Вы не хотите иметь один фабричный класс, который вы хотите иметь для каждого фактора питомца.
Все они должны реализовывать интерфейс фабрики Pet.
То, как вы это делаете, каждый раз, когда добавляете нового питомца, вам придется редактировать фабрику питомцев, а не просто создавать новый класс фабрики питомцев и использовать его.
В качестве альтернативы каждый класс домашних животных может отвечать за создание своих экземпляров (или дескриптор домашнего животного, который связан с домашним животным. Посмотрите на шаблон метода Factory:
http://en.wikipedia.org/wiki/Factory_method_pattern
http://www.dofactory.com/Patterns/PatternFactory.aspx
По крайней мере, это мое понимание.