4

假设我有这样的课程:

猴鱼类
{
   MonkeyFish(GlobalObjectA & a, GlobalObjectB & b, GlobalObjectC & c);

   私人的:
     GlobalObjectA & m_a;
     GlobalObjectB & m_b;
     GlobalObjectC & m_c;
}

如果没有工厂,我需要执行以下操作才能实例化MonkeyFish.

全局对象A a;
全局对象B b;
全局对象 C c;

主函数()
{
  MonkeyFish * monkey_fish = new MonkeyFish(a, b, c);
  猴子鱼->去();
}

另一方面,如果我有MonkeyFishFactory,似乎我必须这样做:

全局对象A a;
全局对象B b;
全局对象 C c;

主函数()
{
  MonkeyFishFactory mf_factory(a, b, c);
  MonkeyFish * monkey_fish = mf_factory.buildMonkeyFish("Bob");
  猴子鱼->去();
}
  1. 我仍然有全局对象。

  2. 即使 MonkeyFishFactory 本身在GlobalObjects内部创建了(所以它们现在在 MonkeyFishFactory 内部而不是真正的全局变量中),看起来 MonkeyFishFactory本身仍然需要是一个全局对象,以便我可以随时访问它来创建一个MonkeyFish.

在这种情况下,工厂模式与全局状态不是一回事吗?

(我目前的假设是全局状态是一件坏事,消除它是一件好事。)

4

8 回答 8

7

你在这里混淆概念吗?

当您返回隐藏在抽象接口后面的具体类的实例时,通常会应用工厂模式。这个想法是调用者将只看到接口,甚至不必知道对象的具体类型是什么。这一切都是关于基于参数创建对象实例,并将与决定创建什么对象相关的逻辑与创建对象的用户解耦。

您所描述的是 Singleton(或 MonoState)和 Factory 的混合物。你的工厂有状态,所以它不能变成静态的。在这种情况下,您将需要应用类似于 Singleton 模式的东西来控制单个 Factory 实例的创建,其中隐藏了适当的全局变量:

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();

Singleton模式控制工厂实例的创建。该Factory模式隐藏了围绕创建实现IMonkeyFish接口的对象的细节。好东西(TM)是隐藏全局状态并将MonkeyFish具体细节与创建实例解耦。

不过,使用这些东西的用法或正确性Singleton是另一个问题。可能还有一堆关于它的线程。

于 2009-03-05T21:30:11.143 回答
6

全局状态本身并不是一件坏事。 公共全局状态是一件坏事。工厂模式有助于封装全局状态,这是一件好事。

于 2009-03-05T21:01:22.133 回答
5

工厂中没有全局状态。它只是创建对象。由于它在工厂中没有任何状态。全球化是可以的。

于 2009-03-05T21:02:00.493 回答
3

您不必离开全局对象。猴鱼工厂应按需创建那些 GlobalOjectA|B|C。使用 switch 或 if inside 方法来确定是哪一个。

于 2009-03-05T21:03:03.813 回答
3

您已经封装了对工厂中对象创建的控制。你希望你的实例化细节被隐藏起来,而不是在你需要新 MonkeyFish 的任何地方复制。想想测试、单一职责和得墨忒耳法则。为什么你的班级想要使用 MonkeyFish 需要了解构建一个 MonkeyFish 所需的工作。如果你想测试 MonkeyFish 怎么办?如果你没有封装创建细节,你会怎么做?

于 2009-03-05T21:20:12.850 回答
3

工厂类的工作是实例化一个对象并将其传回给调用者;不要选择使用哪个全局实例化对象。因此,您的工厂示例不正确。它应该是:

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

注意,没有全局对象,并且 MonkeyFishFactory 没有被实例化。

于 2009-03-05T21:31:12.093 回答
1

我认为您正在考虑单例模式,而不是工厂模式。在单例模式中,你只有一个类的实例,这基本上使它相当于一个全局对象,除非它没有附加全局变量。

于 2009-03-05T21:23:03.750 回答
1

如果你想得到一个好的答案,你应该说明你的约束和要求。要得到一个好的答案,最重要的是知道要问什么问题。

在您提供的代码片段中,您决定使用全局变量,但这与您是否使用工厂无关。如果您使用仍然依赖于这些全局变量的工厂,那么您只需将另一段代码与其余代码堆积起来。

尝试清楚地说明您要达到的目标,您可能会得到更好的答案。

于 2009-03-05T21:35:22.050 回答