Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.)

like image 655
Runcible Avatar asked Nov 28 '22 13:11

Runcible


2 Answers

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.

like image 156
D.Shawley Avatar answered Dec 18 '22 03:12

D.Shawley


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.

like image 34
Eddie Avatar answered Dec 18 '22 02:12

Eddie