开发者

Factory pattern, implementing a dynamic list of factories

I'm implementing an abstract factory pattern (in c++), but there is a slight problem.

I'd like to avoid creating a place which must know at compile time what factories exist.

Usually in the examples I see something like this.

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

I could do something like this, but I want better!

What I have in mind is that the Factory base class would have a list of Factories, each class inherited from Factory would create a static instance and add that instance to the list, through a pr开发者_JS百科otected class function in Factory.

However, I can't figure out a way to do this without playing Russian Roulette with static object initialization.


To avoid problems with static initialization order, you can make the list a static member of a function getFactoryList(). This will then ensure that the list exists when the protected constructor needs to add a factory to the list.

You'll then want to add a virtual method to Factory to determine if a given factory should be used. Hopefully only one factory is eligible for use at a time, so that the order that the factories got created does not change which factory is returned.


Somthing Simple:

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;
        }
};


How would you benefit form such design? I mean, even when you had that list, you would have to select that factory somehow, based on some criteria.

Try Inversion Of Control pattern instead.

If Class A needs to create an object, pass factory to that class.

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

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

Then you would decide which factory to use on the "higher level". Factory may came form the source, form plugin etc.


I use a pattern to collect instances of subclasses. This is the bare bones of it couched in terms of a factory:

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;

You still need a way of searching the list for the correct factory to use, and my macro FACTORYINSTANCE just evaluates to a unique name in order to invoke its own constructor.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜