2011-10-21 82 views
0

类型映射假设我有两套相关类型的,例如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"; 
    } 
}; 

坦率地说,我不知道我在这里的任何改进:更相当多的我还有我的字符串映射,沿可读性较差的代码行...

在第一次执行第二次执行时是否有任何优点,并且有什么方法可以摆脱该映射吗?

+0

我不太确定你想达到什么目的?是否有某种你想要解决的现实生活问题? –

+0

你可以添加'静态Offspring * Animal :: createOffspring()= 0;'?这将使这个_REALLY_变得容易。否则,你将不得不用一个枚举来替换你的字符串。 –

+1

@MooingDuck我认为你的意思是'virtual'而不是static'在你的评论中。 –

回答

1

这看起来像是双派遣的经典案例。用C++解决这个问题的一种模式是Visitor pattern

class Offspring; 
class OffspringFactory; 

class Animal { 
public: 
    // ... rest of Animal class ... 

    virtual Offspring* acceptOffspringFactory(OffspringFactory& factory)const = 0; 
}; 

class OffspringFactory { 
public: 
    Offspring* createCatOffspring() 
    { 
     return new Kitten; 
    } 

    // ... one createXOffspring() for each type of Animal 

    Offspring* getOffspring(const Animal& a) 
    { 
     return a.acceptOffspringFactory(*this); 
    } 
}; 

Offspring* Cat::acceptOffspringFactory(OffspringFactory& factory)const 
{ 
    return factory.createCatOffspring(); 
} 

// etc for rest of Animal classes 

现在,我在你的问题再看看,你不表示该工厂是抽象的,所以真正你可以破除的工厂全部,如果你可以像@MooingDuck提到添加一个方法。

+0

我没有看到双重派遣来自哪里。工厂方法在* one *类型上是多态的:动物类。 –

+0

@AndréCaron事实上,这就是为什么我用后续声明修改了我的答案。我写了原始代码,期望OffspringFactory将是一个抽象工厂。 –

+0

@KurtS感谢您的建议,我觉得可能有些事情我可以在这里用一点思考。主要的问题(我没有真正意识到,直到阅读这里的回复)是我不能直接修改Animal和Offspring类,因为它们来自第三方库。 – atkins