【问题标题】:Is a "factory" method the right pattern?“工厂”方法是正确的模式吗?
【发布时间】:2010-03-11 03:56:46
【问题描述】:

所以我正在努力改进现有的实现。我有许多多态类,它们都组成更高级别的容器类。我目前正在处理的问题是更高级别的容器类,嗯,很糟糕。它看起来像这样,我真的没有问题(因为容器中的多态类应该是公共的)。我真正的问题是构造函数......

/*
 * class1 and class 2 derive from the same superclass
 */
class Container 
{
  public: 
   boost::shared_ptr<ComposedClass1> class1;  
   boost::shared_ptr<ComposedClass2> class2;
  private:
   ...
}

/*
 * Constructor - builds the objects that we need in this container. 
 */ 
Container::Container(some params)
{
  class1.reset(new ComposedClass1(...));
  class2.reset(new ComposedClass2(...));
}

我真正需要的是让这个容器类更易于重用。通过硬编码成员对象并实例化它们,它基本上不是而且只能使用一次。工厂是构建我需要的东西的一种方法(可能通过提供对象列表及其要创建的特定类型?)解决此问题的其他方法?似乎有人应该以前解决过它......谢谢!

【问题讨论】:

  • 关于容器应该做什么的任何细节?它是否试图重新实现多态性?以后会不会将指针重置为其他一些对象?
  • 不,不是重新实现多态性。它只是许多“组件”的容器。一般来说,一组组件会做一些有趣的事情。你可以用一组不同的组件组成一个不同的容器,然后做一些其他有趣的事情。没有理由重置指针 AFAIK。
  • 太抽象了,除非偶然,否则无法给出有用的答案。您是要尝试重用具有不同 class1 和 class2 的相同容器实例,还是尝试重用容器的不同实例?可能 DI(威廉·比林斯利的回应)会有所帮助。
  • 对不起那个汤姆。在重读它时,我同意。您将使用容器的不同实例。所以你会有 Container container1;容器容器2;并且每个都有不同的组合类。

标签: c++ design-patterns factory


【解决方案1】:

Dependency injection 浮现在脑海中。

【讨论】:

  • 感谢您的链接。在阅读链接时,我很确定这就是我正在寻找的东西,因此你赢了! :-) 非常感谢。
【解决方案2】:

如果您更改派生类中创建的类型,即如果 Container 的后代使用 class1 和 class2 的不同后代,则使用工厂方法。

class1* Container::GetClass1; virtual;
{
  return new ComposedClass1;
}

class1* SpecialContainer::GetClass1;
{
  return new SpecialComposedClass1;
}

Container::Container(some params)
{
  class1.reset(GetClass1);
  class2.reset(GetClass2);
}

另一种方法是将 Container 的依赖项的创建与 Container 分离。 对于初学者,您可以将构造函数更改为依赖注入 class1 和 class2。

Container::Container(aclass1, aclass2)
{
  class1.reset(aclass1);
  class2.reset(aclass2);
}

【讨论】:

  • 这种方法通常很好,但你不应该在构造函数中使用工厂方法(构造函数不应该调用虚方法,因为它们在完成构造之前在类上执行)。我会推荐一个抽象工厂,而不是依赖注入。
【解决方案3】:

你知道你可以有第二个构造函数,但不能这样做吗?

Container::Container(some params)
{
    // any other initialization you need to do
}

然后您可以随意设置 class1 和 class2,因为它们是公开的。

当然不应该,但鉴于这段代码,你可以这样做。

据我所知,从您所描述的情况来看,工厂模式并没有那么有用。

【讨论】:

  • 当然,我可以这样做,但问题是容器的不同实例甚至可能不需要将 Class1 和 Class2 组合到其中。它可能有 Class3、4 和 5 作为组合到其中的对象。试图找到一个通用的方法。
【解决方案4】:

根据您的描述,我建议将抽象工厂传递给构造函数。

class ClassFactory {
public:
   virtual ~ClassFactory
   virtual Class1 * createClass1(...) = 0;  // obviously these are real params not varargs
   virtual Class2 * createClass2(...) = 0;
};

class DefaultClassFactory : public ClassFactory {
    //  ....
};


Container::Container(
    some params, 
    boost::smart_ptr<ClassFactory> factory = boost::smart_ptr<ClassFactory>(new DefaultClassFactory))
{
  class1.reset(factory->createClass1(...));
  class2.reset(factory->createClass1(...));
}

这是一种没有框架的依赖注入形式。普通客户端可以像以前一样透明地使用DefaultClassFactory。其他客户端(例如单元测试)可以注入他们自己的 ClassFactory 实现。

根据您希望如何控制 factory 参数的所有权,这可能是 smart_ptr、scoped_ptr 或引用。引用可以使语法更简洁。

Container::Container(
    some params, 
    ClassFactory & factory = DefaultClassFactory())
{
    class1.reset(factory.createClass1(...));
    class2.reset(factory.createClass1(...));
}

void SomeClient()
{
    Container c(some params, SpecialClassFactory());
    // do special stuff
}

【讨论】:

    【解决方案5】:
    public class factory
    {
        public static Class1 Create()
          {
                return new Class1();
          }
    }
    
    class Class1
    {}
    main()
    {
       Classs1 c=factory.Create();   
    }
    

    【讨论】:

      【解决方案6】:

      总的来说,我同意汤姆斯的评论:信息不足。

      根据您的说明:

      它只是多个“组件”的容器

      如果组件列表不同,请在容器上提供 Add/Enumerate/Remove 方法。

      如果应该为容器的每个实例固定组件列表,请提供具有方法的构建器对象

      Builder.AddComponent
      Builder.CreateContainer
      

      第一个允许重用容器,但根据我的经验,通常最终会更复杂。第二个通常需要一种交换/替换容器的方法,但最终更容易实现。

      依赖注入库可以帮助您在应用程序之外配置实际类型(尽管我仍然需要了解为什么这是一个巨大的飞跃)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-29
        • 1970-01-01
        • 2019-08-23
        • 2012-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多