【问题标题】:What things are best not done in a constructor?在构造函数中最好不要做哪些事情?
【发布时间】:2010-10-06 04:41:48
【问题描述】:

我首先起草了一个问题:“在构造函数上执行单元测试的最佳方法是什么(例如,PHP5 中的 __construct())”,但是在阅读相关问题时,我看到几个 cmets 似乎建议在构造函数中设置成员变量或执行任何复杂的操作。

这里所讨论的类的构造函数接受一个参数,对其执行一些操作(确保它通过嗅探测试,并在必要时对其进行转换),然后将其隐藏在一个成员变量中。

我认为这样做的好处是:

1) 客户端代码总是 肯定有这个价值 每当一个对象的成员变量 这个类的实例化了,并且

2) 它在客户端代码中节省了一步 (其中之一可能是 错过),例如,

$Thing = new Thing;
$Thing->initialize($var);

我们什么时候可以这样做

$Thing = new Thing($var);

并完成它。

这是禁忌吗?如果是,为什么?

【问题讨论】:

    标签: php oop constructor


    【解决方案1】:

    你不应该把东西放在只应该在创建类时运行一次的构造函数中。

    解释一下。

    如果我有一个数据库类。其中构造函数是与数据库的连接 所以

    $db = new dbclass;
    

    现在我已连接到数据库。

    然后我们有一个使用数据库类中的一些方法的类。

    class users extends dbclass
    {
        // some methods
    }
    
    $users = new users 
    // by doing this, we have called the dbclass's constructor again
    

    【讨论】:

    • 在这种情况下,我宁愿传入一个 dbclass 的实例,或者将其用作单例,而不是扩展类本身。
    • 是的,有办法解决这个问题,但这只是一个例子。
    • 如果您不想要该功能,您可以覆盖用户对象中的构造函数。还有一些语言,比如 C#,根本不继承构造函数。
    【解决方案2】:

    构造函数是用来初始化对象的,所以

    $Thing = new Thing($var);
    

    完全可以接受。

    【讨论】:

      【解决方案3】:

      我的经验法则是对象应该在构造函数完成后就可以使用了。但通常有许多选项可以在之后进行调整。

      我的注意事项清单:

      • 构造函数应为对象设置基本选项。
      • 他们可能应该创建辅助对象的实例。
      • 它们应该获取资源(文件、套接字等),除非对象显然是某些资源的包装器。

      当然,没有例外,没有规则。重要的是你要考虑你的设计和你的选择。使对象使用自然 - 包括错误报告。

      【讨论】:

        【解决方案4】:

        为了提高类的可测试性,保持它的构造函数尽可能简单并让它只请求它绝对需要的东西通常是一件好事。 YouTube 上有一个出色的 presentation,作为 Google 的“清洁代码讲座”系列的一部分,详细解释了这一点。

        【讨论】:

        • +1 我同意。我们有大量代码,构造函数实际上直接打开文件以读取一些配置信息。在某些方面,它使这些对象易于使用,但编写单元测试是不可能的。还好我们没有单元测试 ;-)
        【解决方案5】:

        这在 C++ 讨论中出现了很多,我得出的一般结论是:

        如果一个对象没有获取任何外部资源,成员必须在构造函数中初始化。这涉及在构造函数中完成所有工作。

        • (x, y) 坐标(或实际上只是一个美化元组的任何其他结构)
        • 美国各州缩写查找表

        如果一个对象获得了它可以控制的资源,它们可以在构造函数中分配

        • 打开文件描述符
        • 分配的内存
        • 指向外部库的句柄/指针

        如果对象获得了它不能完全控制的资源,它们必须在构造函数之外分配

        • TCP 连接
        • 数据库连接
        • 弱参考

        总有例外,但这涵盖了大多数情况。

        【讨论】:

          【解决方案6】:

          取决于您要构建的系统类型,但总的来说,我认为构造函数最好仅用于初始化对象的“状态”,而不是执行任何状态转换本身。最好让它设置默认值。

          然后我在我的对象中编写一个“句柄”方法来处理诸如用户输入、数据库调用、异常、排序规则等等之类的事情。这个想法是,这将根据外力(用户输入、时间等)处理对象所处的任何状态。基本上,所有可能改变对象状态并需要额外操作的事物都会在对象。

          最后,我在类中加入了一个 render 方法来向用户展示一些有意义的东西。这仅向用户表示对象的状态(无论可能是什么)。

          __construct($arguments)
          句柄()
          渲染(异常 $ex = null)

          【讨论】:

            【解决方案7】:

            __construct 魔术方法很好用。您在许多框架和应用程序中看到初始化的原因是因为该对象正在被编程为接口,或者它正在尝试制定单例/getInstance 模式。

            这些对象通常被拉入上下文或控制器,然后由其他更高级别的对象调用它们的通用接口功能。

            【讨论】:

              【解决方案8】:

              你绝对应该避免让客户不得不打电话

              $thing->initialize($var)
              

              那种东西绝对属于构造函数。让他们调用这个对客户端程序员来说是不友好的。有一个(有点争议的)学派说你应该编写类,以便对象永远处于无效状态——而“未初始化”是一种无效状态。

              但是,出于可测试性和性能的原因,有时最好将某些初始化推迟到对象生命周期的后期。在这种情况下,惰性求值是解决方案。

              很抱歉将 Java 语法放在 Python 答案中,但是:

              // Constructor
              public MyObject(MyType initVar) {
                    this.initVar = initVar;
              }
              
              private void lazyInitialize() {
                  if(initialized) {
                      return
                  }
                  // initialization code goes here, uses initVar
              }
              
              public SomeType doSomething(SomeOtherType x) {
                  lazyInitialize();
                  // doing something code goes here
              }
              

              您可以对延迟初始化进行分段,以便仅对需要它的部分进行初始化。例如,在 getter 中这样做很常见,只是为了影响所获得的值。

              【讨论】:

                【解决方案9】:

                构造函数的工作是建立实例的invariants

                任何对它没有贡献的东西最好远离构造函数。

                【讨论】:

                  【解决方案10】:

                  如果 $var 对于 $Thing 的工作是绝对必要的,那么它就是 DO

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-09-11
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-07-16
                    • 2014-02-07
                    相关资源
                    最近更新 更多