Стоимость отражения при использовании фабрики - PullRequest
2 голосов
/ 02 июня 2009

Хорошие люди от stackoverflow,

Как всегда, я пишу фабрику для динамического создания объектов.

Для схематизации у меня есть четыре типа:

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 (...)
    {
        ...
    }
}

Голоса открыты!

edit: вопрос касается производительности отражения, а не фабричного дизайна.

Ответы [ 5 ]

1 голос
/ 02 июня 2009

Поскольку ваш 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 в Фабричном классе , который будет указывать с конкретным Pet, который вы хотите создать. Википедия имеет простой пример с Pizza .

1 голос
/ 02 июня 2009

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

Вы можете либо:

0 голосов
/ 17 июня 2013

Мой английский ужасен, поэтому я надеюсь, что правильно понял ваш вопрос.

Сколько у вас домашних животных?

если у вас есть 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-framework или написать свой собственный (например, вы можете создать тип авто-поиска):

C # Автосканирующая фабрика

0 голосов
/ 02 июня 2009

Вы не хотите иметь один заводской класс, который хотите иметь классы факторий для каждого типа питомца.

Все они должны реализовывать интерфейс фабрики Pet.

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

В качестве альтернативы каждый класс домашних животных может отвечать за создание своих экземпляров (или дескриптор домашнего животного, который связан с домашним животным. Посмотрите на шаблон метода Factory:

http://en.wikipedia.org/wiki/Factory_method_pattern

http://www.dofactory.com/Patterns/PatternFactory.aspx

По крайней мере, это мое понимание.

0 голосов
/ 02 июня 2009

Ваше третье решение (с виртуальным методом) определенно вышло: класс PetDescriptor не должен знать обо всех его производных классах (вам придется добавлять новый метод IsXXX каждый раз, когда вы создаете класс XXXDescriptor).

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

...