为什么不"在对象构造函数中实例化一个新对象"?

Voi*_*cus 21 php oop

我回答了一个问题(链接),我在另一个类的构造函数中使用了新对象的创建,这里是示例:

class Person {
  public $mother_language;

  function __construct(){ // just to initialize $mother_language
    $this->mother_language = new Language('English');
}
Run Code Online (Sandbox Code Playgroud)

我收到了用户"Matija"(他的个人资料)的评论,他写道:你永远不应该在对象consturctor中实例化一个新对象,应该从外部推送依赖,所以使用这个类的人都知道这个类依赖于什么!

一般来说,我同意这一点,我理解他的观点.

但是,我过去常常这样做,例如:

  • 作为私有属性,其他类给我的功能,我可以解决不复制代码,例如我可以创建一个列表(类实现ArrayAccess接口)的对象),这个类将用于另一个类,具有这样的列表对象,
  • 一些类用于示例DateTime对象,
  • 如果我include(或自动加载)依赖类,一个应该没有错误的问题,
  • 因为依赖对象可以是非常大的数,将它们全部传递给类构造函数可能会很长而且不清楚,例如

    $color = new TColor('red'); // do we really need these lines?
    $vin_number = new TVinNumber('xxx');
    $production_date = new TDate(...);
    ...
    $my_car = new TCar($color, $vin_number, $production_date, ...............);
    
    Run Code Online (Sandbox Code Playgroud)
  • 因为我在Pascal"出生",然后在Delphi,我有一些习惯.在Delphi(以及FreePascal作为其竞争对手)中,这种做法经常发生.例如,有一个TStrings类处理字符串数组,并且存储它们不使用arrays而是另一个类TList,它提供了一些有用的方法,而TStrings只是某种类型的接口.该TList对象是私有声明的,并且不能从外部访问,但是getter和setter TStrings.

  • (不重要,但有些原因)通常我是使用我的课程的人.

请解释一下,避免在构造函数中创建对象真的很重要吗?

我已经阅读了这个讨论,但仍然不清楚.

Sch*_*eis 12

是的,它确实是.然后,您可以清楚地了解对象需要什么才能构建.传入的大量依赖对象是代码气味,也许你的类做得太多,应该在多个较小的类中被打破.

如果要测试代码,则传递依赖对象的主要优点是.在您的示例中,我不能使用假的语言类.我必须使用实际的类来测试Person.我现在无法控制语言的行为以确保Person正常工作.

这篇文章有助于解释为什么这是一件坏事以及它造成的潜在问题.http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/

UPDATE

除了测试之外,传入依赖对象还可以使您的代码更加明确,灵活和可扩展.引用我链接到的博文:

当协作者构造与初始化混合在一起时,它表明只有一种方法可以配置类,从而关闭可能存在的重用机会.

在您的示例中,您只能创建将"英语"作为语言的人.但是当你想要创造一个说"法语"的人时呢?我无法定义.

作为创建对象,并在通过他们,是的整个目的Factory格局http://www.oodesign.com/factory-pattern.html.它会创建依赖项并为您注入它们.因此,您可以向它询问将以您想要的方式初始化的对象.Person对象不应该决定它需要什么.

  • @ITroubs:这是该策略的另一个问题.如果您需要为一个测试包含一个版本的类,然后为另一个测试包含该类的另一个版本,该怎么办?您将包括同一类的两个不同定义. (2认同)
  • @Schleis谢谢.我在这里找到了更清晰的解释http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/ (2认同)

Lig*_*ica 7

原来的评论对我来说似乎很愚蠢.

没有理由害怕管理资源的课程.实际上,类提供的封装非常适合此任务.

如果你限制自己只是从外部推动资源,那么应该管理这些资源呢?意大利面程序代码?哎呀!

尽量避免相信你在互联网上阅读的所有内容.

  • 我在他提到的讨论中对问题的回答有一个真正的观点.当你实例化时,可能会有一些课真的需要时间.如果那时你的班级几乎从不或只是在一些非常罕见的情况下使用该类,那么为什么要在构造函数中实现它呢?这只会浪费性能! (3认同)
  • @ITroubs:你怎么能谈论表演呢?你有什么想法吗?首先要关注代码清晰度,而不是性能. (3认同)