【问题标题】:The "Self-Factory" Pattern“自工厂”模式
【发布时间】:2009-06-24 21:55:27
【问题描述】:

我不知道这个有没有正式的名字,但我一直在玩我喜欢称之为“自工厂”的模式。基本上,这是一个抽象基类充当自己的工厂的时候。让我解释一下:

我的系统中有 Foo 对象和 Bar 对象,它们通过接口 FooInterface 和 BarInterface 使用。我需要为我的客户提供正确类型的 Foo 和 Bar。在编译时决定创建哪个具体的 Foo 对象。例如,如果你在 win32 上编译,你只想创建 Win32Foo 对象,如果你在 OSX 上编译,你只想创建 OSXFoo 对象等等。但是,创建哪个具体的 Bar 对象是在运行时根据键字符串决定的。

现在,我的问题是关于实施该方案的最佳方式。我想出的一种方法是使用常规工厂:

shared_ptr<FooInterface> foo = FooFactory::create();
shared_ptr<BarInterface> happyBar = BarFactory::create("Happy");
shared_ptr<BarInterface> sadBar = BarFactory::create("Sad");

另一种方法是使用我所说的“自工厂”:

shared_ptr<FooInterface> foo = FooInterface::create();
shared_ptr<BarInterface> happyBar = BarInterface::create("Happy");
shared_ptr<BarInterface> sadBar = BarInterface::create("Sad");

从可用性的角度和架构的角度来看,每种方法的优缺点是什么?

【问题讨论】:

  • 我认为您建议的自工厂也称为原型模式。您可能可以查看有关该模式的文献以获取想法。

标签: c++ factory


【解决方案1】:

我会做出改进:

shared_ptr<FooInterface> foo = Factory<FooInterface>::create();
shared_ptr<BarInterface> happyBar = Factory<BarInterface>::create("Happy");
shared_ptr<BarInterface> sadBar = Factory<BarInterface>::create("Sad");

你会声明:

template <class I>
struct Factory { };

然后对于需要工厂的每个接口,您可以这样做:

template <>
struct Factory<FooInterface>
{
    static FooInterface create();
};

这允许您将工厂实现与接口声明分开,但仍使用类型系统在编译时绑定它们。

【讨论】:

    【解决方案2】:

    工厂有两种常见用途:

    1) 在运行时根据参数和/或全局状态(例如配置)确定动态多态类型。你的模式就是这样做的。

    2) 依赖注入:不是使用静态函数来创建对象,而是使用工厂object,这样返回的对象的类型可以由调用者配置,方法是传入任何工厂想。这些模式都没有提供这一点。此外,您的第二种模式甚至不允许静态依赖注入(通过具有将工厂类作为模板参数的模板函数),因为接口和工厂是相同的。

    因此,您的模式(以及您的常规工厂)的一个缺点是依赖注入不受真正支持。只有一个函数可以调用来获取一个 FooInterface 对象,那就是 FooInterface::create()。我不会争论依赖注入为什么有用,只是指出如果你这样构建,你就不能使用它。

    【讨论】:

      【解决方案3】:

      通常工厂负责创建整个类层次结构的对象。因此,在您的示例中,您将拥有 Win32Factory、OSXFactory 等。这样做的一个优点是您只需在工厂创建期间选择一次特定的实现(win32/unix/etc),但如果您使用类接口,您有一直提供操作系统信息。

      如果您只有两个类(Foo 和 Bar),我不确定是否值得为它们创建工厂,而不仅仅是使用接口的 create 方法。

      哦,当一个接口有一个方法来创建它的类型的对象时,它被称为factory method pattern

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-09-25
        • 1970-01-01
        • 2017-07-31
        • 2016-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多