Question

Let's say I have a class like this:

class MonkeyFish
{
   MonkeyFish( GlobalObjectA & a, GlobalObjectB & b, GlobalObjectC & c);

   private:
     GlobalObjectA & m_a;
     GlobalObjectB & m_b;
     GlobalObjectC & m_c;
}

Without a factory, I need to do the following in order to instantiated a MonkeyFish.

GlobalObjectA a;
GlobalObjectB b;
GlobalObjectC c;

int main()
{
  MonkeyFish * monkey_fish = new MonkeyFish(a, b, c);
  monkey_fish->go();
}

On the other hand, if I have a MonkeyFishFactory, it seems like I have to do this:

GlobalObjectA a;
GlobalObjectB b;
GlobalObjectC c;

int main()
{
  MonkeyFishFactory mf_factory(a, b, c);
  MonkeyFish * monkey_fish = mf_factory.buildMonkeyFish("Bob");
  monkey_fish->go();
}
  1. I still have global objects.

  2. Even if the MonkeyFishFactory itself created the GlobalObjects internally (so they are now inside the MonkeyFishFactory instead of true globals), it seems like the MonkeyFishFactory itself still needs to be a global object so that I can access it anytime I want to create a MonkeyFish.

Isn't the Factory pattern the same thing as global state in this case?

(I'm currently operating under the assumption that global state is a Bad Thing, and eliminating it is a Good Thing.)

Was it helpful?

Solution

Are you confusing concepts here?

The Factory pattern is usually applied when you are returning an instance of a concrete class that hides behind an abstract interface. The idea is that the caller will see just the interface and doesn't even have to know what the concrete type of the object is. It is all about creating an object instance based on parameters and decoupling the logic associated with deciding what object to create from the user creating the object.

What you are describing is a mixture of Singleton (or MonoState) and Factory. Your Factory has state so it cannot be made static. In this case, you will need to apply something like the Singleton pattern to control the creation of a single Factory instance with the appropriate globals hidden within it:

class IMonkeyFish {
public:
    virtual ~IMonkeyFish() = 0;
    virtual void go() = 0;
};

class Factory {
public:
    static Factory& instance();
    IMonkeyFish* createMonkeyFish();
protected:
    Factory(GlobalObjectA& a, GlobalObjectB& b, GlobalObjectC& c);
private:
    static Factory *theInstance;
    GlobalObjectA&  instanceOfA;
    GlobalObjectB&  instanceOfB;
    GlobalObjectC&  instanceOfC;
};

Factory& factory = Factory::instance();
IMonkeyFish* fishie = factory.createMonkeyFish();
fishie->go();

The Singleton pattern governs the creation of the factory instance. The Factory pattern hides the details surrounding the creation of objects that implement the IMonkeyFish interface. The Good Thing (TM) is the hiding of the global state and decoupling of the MonkeyFish concrete details from creating an instance.

The usage or correctness of using the Singleton stuff is a whole other issue though. There are probably a bunch of threads floating around about that as well.

OTHER TIPS

Global state is not in-and-of-itself a Bad Thing. Public global state is a Bad Thing. The Factory pattern helps encapsulate global state, which is a Good Thing.

There are no global state in the Factory. It just creates objects. Since it not any state in the factory. It's OK to be global.

You don't have to leave global objects. Monkey fish factory should create those GlobalOjectA|B|C on demand. Using switch or if inside method to determine which one.

You have encapsulated control over creation of objects in a factory. You want your instantiation details to be hidden away, not reproduced everywhere you need a new MonkeyFish. Think about testing, Single Responsibility, and the Law of Demeter. Why should your class that wants to use a MonkeyFish need to know anything about the work it takes to build one. What if you want to test MonkeyFish? How would you do it if you didn't have creation details encapsulated?

The job of a factory class is to instantiate an object and pass it back to the caller; not to pick which global instantiated object to use. So, your factory example is incorrect. It should be:

int main()
{
  MonkeyFish * monkey_fish = MonkeyFishFactory::buildMonkeyFish("Bob");
  monkey_fish->go();
}

Notice, no global objects, and MonkeyFishFactory is not instantiated.

I think you are thinking of the Singleton Pattern, not the Factory Pattern. In the singleton pattern you only have on instance of a class which basically makes it the equivalent of a global object except there is no global variable attached to it.

You should state your constraints and requirements if you want to get a good answer. The most important thing to get a good answer is knowing what question to ask.

In the code snippets you provided you have decided to use globals, but that has nothing to do with whether you use a Factory or not. If you use a factory that still depends on those globals, then you just have another piece of code to pile up with the rest.

Try to state clearly what you are trying to achieve and you will probably get a better answer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top