Да предположим, че имам два набора от свързани типове, например Animal
s и техните Offspring
:
/* Animal types */
struct Animal
{
virtual string getType() const = 0;
};
struct Cat : public Animal
{
virtual string getType() const { return "Cat"; }
};
struct Dog : public Animal
{
virtual string getType() const { return "Dog"; }
};
/* Offspring types */
struct Offspring
{
virtual string getType() const = 0;
};
struct Kitten : public Offspring
{
virtual string getType() const { return "Kitten"; }
};
struct Puppy : public Offspring
{
virtual string getType() const { return "Puppy"; }
};
Опитвам се да внедря фабрика, която при даден Animal
ще върне обект от асоциирания тип Offspring
(напр. ако Animal
всъщност е Dog
, фабриката ще върне Puppy
).
Първият ми опит за внедряване на такава фабрика изглежда така:
// First attempt at OffspringFactory
class OffspringFactory1
{
static Offspring* createKitten() { return new Kitten(); }
static Offspring* createPuppy() { return new Puppy(); }
public:
// Create an Offspring according to the Animal type
static Offspring* getOffspring(const Animal& a)
{
// Static mapping of Animal types to Offspring factory functions
static map<string, Offspring* (*)()> factoryMap;
if (factoryMap.empty())
{
factoryMap["Dog"] = &createPuppy;
factoryMap["Cat"] = &createKitten;
}
// Lookup our Offspring factory function
map<string, Offspring* (*)()>::const_iterator fnIt = factoryMap.find(a.getType());
if (fnIt != factoryMap.end())
return fnIt->second();
else
throw "Bad animal type";
}
};
Работи добре, но прибягнах до базирано на низове картографиране, а не нещо чисто базирано на тип. Опитвайки се да премина към по-базирана на тип реализация, стигнах до това:
// Second attempt at OffspringFactory
class OffspringFactory2
{
// Mapping Animal types to Offspring types
template<typename TAnimal> struct OffspringMapper;
template<>
struct OffspringMapper<Cat> {
typedef Kitten offspring_type;
};
template<>
struct OffspringMapper<Dog> {
typedef Puppy offspring_type;
};
// Factory method
template<typename TAnimal>
static Offspring* create() { return new OffspringMapper<TAnimal>::offspring_type(); }
public:
// Create an Offspring according to the Animal type
static Offspring* getOffspring(const Animal& a)
{
// Static mapping of Animal type strings to Offspring factory functions
static map<string, Offspring* (*)()> factoryMap;
if (factoryMap.empty())
{
factoryMap["Dog"] = &create<Dog>;
factoryMap["Cat"] = &create<Cat>;
}
// Lookup our Offspring factory function
map<string, Offspring* (*)()>::const_iterator fnIt = factoryMap.find(a.getType());
if (fnIt != factoryMap.end())
return fnIt->second();
else
throw "Bad animal type";
}
};
Честно казано, не съм сигурен, че съм подобрил нещо тук: все още имам моето картографиране на низове, заедно с още доста редове по-малко четим код...
Има ли предимство във второто внедряване пред първото и има ли някакъв начин да се отърва от тази карта?
static Offspring* Animal::createOffspring() =0;
? Това би направило това НАИСТИНА лесно. В противен случай ще трябва просто да замените вашите низове с enum. - person Mooing Duck   schedule 21.10.2011virtual
неstatic
в коментара си. - person Kurt Stutsman   schedule 21.10.2011virtual Offspring* Animal::createOffspring() =0;
- person Mooing Duck   schedule 21.10.2011