应该在构造函数中执行可能需要一些时间的操作,还是应该构造对象然后稍后进行初始化.
例如,当构造表示目录结构的对象时,应该在构造函数中完成对象及其子对象的填充.显然,目录可以包含目录,而目录又可以包含目录等.
这个优雅的解决方案是什么?
Odd*_*ing 48
总结一下:
至少,构造函数需要将对象配置为其不变量为true的点.
您选择的不变量可能会影响您的客户.(对象是否承诺随时可以访问?或者仅在某些状态下?)构建者可以预先处理所有设置可能会使生活更简单为班级的客户.
长期运行的构造函数本身并不坏,但在某些情况下可能会很糟糕.
对于涉及用户交互的系统,任何类型的长时间运行方法都可能导致响应性差,应该避免.
延迟计算直到构造函数之后可能是有效的优化; 可能结果是没有必要执行所有工作.这取决于应用,不应过早确定.
总的来说,这取决于.
Soa*_*Box 24
您通常不希望构造函数进行任何计算.使用该代码的其他人不会期望它比基本设置更多.
对于你正在谈论的目录树,"优雅"的解决方案可能不是在构造对象时构建完整的树.相反,按需构建它.使用你的对象的人可能并不真正关心子目录中的内容,所以首先让你的构造函数列出第一级,然后如果有人想要下降到特定的目录,那么在他们请求时构建树的那一部分它.
Joh*_*itb 13
所需的时间不应成为不将某些东西放入构造函数的理由.您可以将代码本身放入私有函数中,并从构造函数中调用它,只是为了使构造函数中的代码保持清晰.
但是,如果您想要做的事情不需要给对象一个定义的条件,并且您可以在以后第一次使用时执行这些操作,这将是一个合理的论据,可以将它放出来并在以后执行.但是不要让它依赖于你的类的用户:这些东西(按需初始化)必须对你的类的用户完全透明.否则,对象的重要不变量可能很容易破坏.
Kei*_*thB 10
这取决于(典型的CS答案).如果您在启动时为长时间运行的程序构造对象,那么在构造函数中执行大量工作就没有问题.如果这是预期快速响应的GUI的一部分,则可能不合适.与往常一样,最好的答案是首先尝试最简单的方式,从那里进行配置和优化.
对于这种特定情况,您可以对子目录对象进行延迟构造.仅为顶级目录的名称创建条目.如果访问它们,则加载该目录的内容.当用户演示目录结构时再次执行此操作.
构造函数最重要的工作是为对象提供初始有效状态.在我看来,构造函数最重要的期望是构造函数应该没有副作用.
我同意长期运行的构造函数本质上并不坏。但我会争辩说,你几乎总是做错了。我的建议类似于 Hugo、Rich 和 Litb 的建议:
I/O 问题示例:许多硬盘都存在问题,它们会进入一种状态,即在 100 毫秒甚至数千毫秒内不为读取或写入提供服务。第一代和第一代固态硬盘经常这样做。用户现在有办法知道你的程序只是挂了一会儿——他们只是认为这是你的有缺陷的软件。
当然,长时间运行的构造函数的坏处取决于两件事:
现在,如果“长”只是几个 100 个额外的工作时钟周期,那么它并不是很长。但是构造函数正在进入 100 微秒范围,我建议它很长。当然,如果您只实例化其中一个,或者很少实例化它们(比如每隔几秒一次),那么由于此范围内的持续时间,您不太可能看到问题。
频率是一个重要因素,如果您只构建其中的几个,500 us ctor 不是问题:但是创建一百万个会造成严重的性能问题。
让我们谈谈您的示例:在“类目录”对象中填充目录对象树。(注意,我假设这是一个带有图形用户界面的程序)。在这里,您的 CTOR 持续时间不取决于您编写的代码 - 它的被告是枚举任意大的目录树所需的时间。这在本地硬盘上已经够糟糕的了。它在远程(网络)资源上的问题更大。
现在,想象一下在您的用户界面线程上执行此操作 - 您的 UI 将在数秒、10 秒或可能的数分钟内停止。在 Windows 中,我们称之为 UI 挂起。它们很糟糕很糟糕(是的,我们有它们……是的,我们努力消除它们)。
UI 挂起会让人们非常讨厌你的软件。
正确的做法是简单地初始化您的目录对象。在可以取消的循环中构建您的目录树并使您的 UI 保持响应状态(取消按钮应始终有效)
从历史上看,我已经对构造函数进行了编码,以便一旦构造函数方法完成,对象就可以使用了。涉及多少代码取决于对象的要求。
例如,假设我需要在详细信息视图中显示以下 Company 类:
public class Company
{
public int Company_ID { get; set; }
public string CompanyName { get; set; }
public Address MailingAddress { get; set; }
public Phones CompanyPhones { get; set; }
public Contact ContactPerson { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
由于我想在详细信息视图中显示有关公司的所有信息,因此我的构造函数将包含填充每个属性所需的所有代码。鉴于这是一个复杂的类型,Company 构造函数也会触发 Address、Phones 和 Contact 构造函数的执行。
现在,如果我正在填充一个目录列表视图,其中我可能只需要 CompanyName 和主要电话号码,那么我可能在该类上有第二个构造函数,该构造函数仅检索该信息并将剩余信息留空,或者我可以创建仅保存该信息的单独对象。这实际上只取决于信息的检索方式和来源。
无论类中的构造函数有多少,我个人的目标都是进行任何必要的处理,为对象做好可能承担的任何任务的准备。