2011-05-04 67 views
2

我正在实现一个抽象工厂模式(在C++中),但有一个小问题。工厂模式,实现工厂动态列表

我想避免创建一个必须在编译时知道工厂存在的地方。

通常在例子中我看到类似这样的东西。

Factory * getFactory() 
{ 
    if(/*we should make factoryA*/) 
    { 
     return FactoryA::instance(); 
    } 
    else if(/*we should return FactoryB*/) 
    { 
     return FactoryB::instance(); 
    } 
    else 
    { 
     return NULL; 
    } 
} 

我可以做这样的事情,但我想要更好!

我心目中的是,工厂的基类将有工厂的名单,从继承厂将创建一个静态实例,该实例中添加到列表中,通过一个受保护类的函数厂每个班

但是,我不能找出一种方法来做到这一点,而不用玩俄罗斯轮盘与静态对象初始化。

+0

什么是你想实现什么?你如何决定应该退回哪个工厂?为什么你想要一个清单,你会如何将正确的工厂拉出清单? – 2011-05-04 13:12:02

+0

FactoryA :: instance()返回什么?它是否返回工厂实例?它是否返回新A的实例?我第一眼看你的代码让我觉得这个函数正在返回工厂。如果是这种情况,你的方法可能是错误的。 – 2011-05-04 13:21:36

+0

@dauphic:这是比较标准的模式。你有一堆工厂对象,你需要在运行时动态决定使用哪些对象。 – 2011-05-04 14:18:13

回答

1

财产以后简单:

class BaseFactory 
{ 
    public: 
     BaseFactory() 
     { 
      std::list<BaseFactory*>& fList = getFactoryList(); 
      fList.push_back(this); 

      // If you are feeling brave. 
      // Write the destructor to remove the object from the list. 
      // 
      // Note C++ guarantees the list will live longer than any of the factories 
      // Because the list will always be completely constructed before any 
      // of the factory objects (because we get the list in the constructor). 
     } 

     static BaseFactory& getFactory() // Don't return a pointer (use a reference) 
     { 
      std::list<BaseFactory*>& fList = getFactoryList(); 
      std::list<BaseFactory*>::iterator i = selectFactory(fList); 

      if (i == fList.end() 
      { 
       static FakeFactory fakeFactory; // Having a fake factory that 
               // that returns fake object 
               // is usually a lot easier than checking for 
               // NULL factory objects everywhere in the code 
               // 
               // Alternatively throw an exception. 
       return fakeFactory; 
      } 

      return *(*i); // return reference 
     } 
    private: 
     static std::list<BaseFactory*>& getFactoryList() 
     { 
      static std::list<BaseFactory*> factoryList; // Notice the static 
      return factoryList; 
     } 
}; 
+0

感谢您的好回答。这是否正确(?):即使在从静态对象的初始化中输入函数的情况下,函数中声明的静态变量也会保证在输入函数时实例化? – 0xbaadf00d 2011-05-05 07:33:17

+0

一旦构造函数完成,就完全构造一个对象。静态存储持续时间(全局变量/静态函数作用域对象)对象按创建的顺序(构造函数的完成)进行维护,并按创建的相反顺序销毁(这全部由标准保证)。全局对象的顺序有点儿含糊但静态的函数对象在首次使用时被初始化。因此,如果一个全局对象从其构造函数调用一个具有静态对象的函数,则该对象将在全局构造函数完成之前完全构造,因此将首先构造 – 2011-05-05 07:57:01

+0

“this”当'Factory'具有多重继承并且'BaseFactory'不是第一个基类时? – q126y 2015-12-10 05:34:01

0

你会从这样的设计中受益吗?我的意思是,即使你有这个清单,你也必须根据某些标准以某种方式选择该工厂。

尝试Inversion Of Control模式代替。

如果A类需要创建一个对象,则将工厂传递给该类。

class A { 
    Factory *f; 
public: 
    A(Factory *f) 
     : f(f) 
    { } 

    void doSomething() 
    { 
     Object o = f->produce(); 
     ... 
    } 
} 

然后您将决定在“更高级别”上使用哪个工厂。工厂可能来源,表格插件等

+0

问题是关于选择工厂。您已经选择了工厂并将工厂交给了对象。在你做这件事之前,你需要找到工厂。 – 2011-05-04 14:14:55

3

为了避免静态初始化顺序的问题,可以使列表成为函数getFactoryList()的静态成员。这将确保当受保护的构造函数需要将一个工厂添加到列表中时该列表存在。

然后,您会想要将一个虚拟方法添加到Factory以确定是否应该使用给定的工厂。希望一次只能有一个工厂有资格使用,以便工厂创建的订单不会改变返回的工厂。

0

我使用模式来收集子类的实例。这是它的基本框架在工厂的措词:

class Factory { 
    public: 
     virtual Foo* makeFoo()=0; 
     ... 
    protected: 
     Factory(){ 
      getFactoryList().push_back(this); 
     } 
    private: 
     FactoryList& getFactoryList(); // Returns static list 
}; 

class FactoryA: public Factory{ 
     Foo* makeFoo(); // I make a Foo my way 
} FACTORYINSTANCE; 

你仍然需要搜索列表中正确的工厂使用的一种方式,我的宏FACTORYINSTANCE只计算为一个唯一的名称,以调用它自己的构造函数。