【问题标题】:Which design to chose for complex object initialization?为复杂的对象初始化选择哪种设计?
【发布时间】:2016-02-11 11:57:00
【问题描述】:

假设我有一个封装了一个(或多个)成员的类,必须以某种方式对其进行初始化,没有它就没有合理的方式使用该类(所以我不想让它成为可选的) . 像这样在其构造函数中运行初始化是否更好:

class MyClass
{
    MyClass()
    {
        if(!obj.initialize()
            throw ...;
    }

private:
    MyObject obj;
}

或者您会建议以下设计:

class MyClass
{
    MyClass()
    {
    }

    bool initialize()
    {
        return obj.initialize();
    }

private:
    MyObject obj;
}

第一个看起来很吸引人,因为我可以保证在构造函数运行后满足使用我的类的所有要求,并且我可以通过抛出异常来报告任何错误。

第二个看起来不错,因为它不会用直觉上不属于那里的东西重载构造函数,特别是当初始化例程变得复杂时,即创建小部件、打开数据库连接、初始化第 3 方库等。在很多我正在使用的遗留代码,ctors 充斥着参数和初始化的东西,可能在这种臃肿的对象构造完成之前运行了数千行代码。尝试将这些重构为更干净的东西在某些时候确实很难,因为涉及的依赖项太多。这就是我提出问题的原因。

我可以看到设计#2 的最大缺点是我需要一个公共初始化例程,客户端必须记住调用它。但是由于这可以并且可能会被遗忘,我必须跟踪和检查所有公共成员的初始化状态,并以某种方式处理错误(可能一个断言就可以了)。如果我选择设计#1,这也会使我的课堂上出现一些不存在的东西。

那么我最好的选择是什么?

【问题讨论】:

  • 对我来说,这听起来像是在自相矛盾:“没有它就没有合理的方法来使用类”,然后是“用直觉上不属于那里的东西重载构造函数”。将对象置于一致状态是构造函数的工作,因此任何需要这样做的东西都应该交给构造函数。
  • 你不必有一个臃肿的构造函数。您仍然可以将代码正确地组织到模块/函数中,然后从构造函数中调用它们。您可以有一个混合解决方案,其中您的 init 方法是私有的,您可以从构造函数中调用它。这样,如果初始化失败,您可以抛出。
  • 你可以创建函数来创建每个子对象(所以一个子对象一行)。
  • 当您无法建立类的不变量时,更喜欢从构造函数中抛出。这样您就不必担心漂浮的无效对象。否则,创建一个将 2 个步骤(创建和初始化)包装在一起的工厂。
  • 如果MyObject的构造函数自己初始化,MyClass就不用费心了。

标签: c++ constructor initialization


【解决方案1】:

“第一个看起来很吸引人,因为我可以保证在构造函数运行后满足使用我的类的所有要求......”

这个必须是这样,否则设计不好。

当构造函数完成时,对象 必须没有任何未定义的行为并且根据其接口规范可用。

但是不是意味着对象需要配置用于特定目的。

我喜欢将初始化配置分开。

例如查看std::fstream。您可以在不打开任何文件的情况下创建一个完全初始化的 fstream 对象

std::fstream fs; // initialized but not configured

它不会表现出未定义的行为,并将根据其接口规范进行操作。

所以你可以使用它的接口来配置它到一个给定的目的——例如读取一个特定的文件:

fs.open("myfile.txt", std::ios::in); // configured

默认构造函数应该做绝对最小值以将对象放入工作顺序,而不必配置它到一个给定的任务。

话虽如此,没有理由不使用 other 构造函数来简化创建配置对象:

std::fstream fs("myfile.txt", std::ios::in); // initialized & configured

【讨论】:

    【解决方案2】:

    将代码从MyObject::initialize 移动到MyObject 的构造函数(如果需要,也可以将throw 移动到)。现在为MyClass 隐式定义的默认构造函数将完成正确的工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-26
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多