简体   繁体   English

选择哪种设计进行复杂对象初始化?

[英]Which design to chose for complex object initialization?

Lets say I have a class encapsulating one (or multiple) member(s) which must in some way be initialized and there is no reasonable way to use the class without it (so I don't want to make it optional). 假设我有一个封装一个(或多个)成员的类,它必须以某种方式进行初始化,没有合理的方法来使用没有它的类(所以我不想让它成为可选的)。 Is it then better to have initialization run in its constructor like so: 在其构造函数中运行初始化是否更好呢:

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

private:
    MyObject obj;
}

or would you suggest the following design: 或者你会建议以下设计:

class MyClass
{
    MyClass()
    {
    }

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

private:
    MyObject obj;
}

The 1st one looks appealing because I can guarantee all requirements for using my class have been met after the constructor has run and I can report any errors by throwing an exception. 第一个看起来很吸引人,因为我可以保证在构造函数运行后满足使用我的类的所有要求,并且我可以通过抛出异常来报告任何错误。

The 2nd looks good because it doesn't overload constructors with stuff that intuitively doesn't belong there, especially once the initialization routine gets complex and ie creates widgets, opens database connections, initializes 3rd party libraries etc. In a lot of legacy code I'm working with, ctors are flooded with parameters and intialization stuff, probably running thousands of code lines before this type of bloated object construction is even done. 第二个看起来不错,因为它不会使构造函数超出直觉上不属于那里的东西,特别是一旦初始化例程变得复杂,即创建小部件,打开数据库连接,初始化第三方库等。在很多遗留代码中我与之合作,ctors充满了参数和初始化的东西,可能在这种类型的膨胀对象构造完成之前运行了数千条代码行。 Trying to refactor these into something cleaner is really hard at some point because there are too many dependencies involved. 试图将这些重构为更干净的东西在某些方面真的很难,因为涉及的依赖性太多了。 That's what motivated my question. 这就是我的问题的动机。

The big disadvantage of design #2 I can see is that I need a public initialization routine which the client must remember to call. 我可以看到设计#2的一大缺点是我需要一个客户端必须记住调用的公共初始化例程。 But since this can and probably will be forgotten, I have to track and check intialization state in all public members and somehow treat errors (probably an assert will do). 但由于这可能并且可能会被遗忘,我必须在所有公共成员中跟踪和检查初始化状态,并以某种方式处理错误(可能是断言会做的)。 This will also clutter my class with stuff that's not there if I chose design #1. 如果我选择设计#1,这也会使我的课程变得杂乱不堪。

So what's my best choice here? 那么这里最好的选择是什么?

"The 1st one looks appealing because I can guarantee all requirements for using my class have been met after the constructor has run ...." “第一个看起来很吸引人,因为我可以保证在构造函数运行后满足使用我的类的所有要求......”

This must be the case otherwise the design is bad. 必须是这种情况,否则设计是不好的。

When the constructor completes then the object must be usable without any undefined behaviour and according to its interface specification. 当构造函数完成时,该对象 必须是可用的,没有任何未定义的行为并且根据其接口规范。

BUT that does not mean the object needs to be configured for a given purpose. 但是,并不意味着需要配置用于特定目的的对象

I like to separate out initialization from configuration . 我喜欢从配置中分离初始化

For example look at std::fstream . 例如,查看std::fstream You can create a completely initialized fstream object without opening any files: 您可以在不打开任何文件的情况下创建完全初始化的fstream对象

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

It does not exhibit undefined behaviour and will operate according to its interface specification. 它没有表现出未定义的行为,并将根据其接口规范进行操作。

So you can use its interface to configure it to a given purpose - for example to read a specific file: 因此,您可以使用其界面将其配置为给定目的 - 例如,读取特定文件:

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

The default constructor should do the absolute minimum to put the object into working order without, necessarily configuring it to a given task. 默认构造函数应该执行绝对最小值以将对象置于工作顺序,而不必将其配置为给定任务。

That being said there is no reason not to have other constructors to make creating configured objects easier: 话虽如此,没有理由不让其他构造函数更容易创建配置对象:

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

Move the code from MyObject::initialize to MyObject 's constructor (the throw as well, if necessary). 将代码从MyObject::initialize移动到MyObject的构造函数(如果需要,也可以throw )。 Now the implicitly-defined default constructor for MyClass will do the right job. 现在, MyClass的隐式定义的默认构造函数将完成正确的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM