【问题标题】:Is a final static class method possible?最终的静态类方法是否可能?
【发布时间】:2012-01-06 21:20:09
【问题描述】:

我需要一个类来继承另一个类。我在基类中有一个静态函数_init(),我不希望在派生类中继承该方法。我尝试了 final 关键字,但它不起作用。我该怎么办?

【问题讨论】:

  • 如果你需要初始化你的代码,你最好使用对象。
  • 首先,为什么不希望基类访问这个方法呢?如果您不希望派生类可以访问它,请将其设为私有。第二个选项是在派生类中覆盖它。
  • 我希望基类访问该方法 _init() 而不是派生类!
  • 我删除了 OOP 标签,因为您正在执行基于类的编程,这基本上只是使用类进行过程编程。
  • +1 给 Zoidberg。这个问题的直接解决方案是将该方法设为私有。

标签: php class inheritance static


【解决方案1】:

你做错了。

只是你希望扩展类没有有方法,这意味着你违反了Liskov's substitution principle ..如果阅读困难:这里是a picture 解释它。

如果您遇到这样的情况,当您在将对象发布到应用程序之前必须对对象执行某种“工作”时,那么您应该为它使用工厂/构建器。 p>

class FooBuilder
{
   public function create( $external_condition )
   {
      $object = new Foo;
      if ( $external_condition->has_happened() )
      {
         $object->set_condition( $external_condition );
      }else{
         $object->do_something_else();
      }
      return $object;
   }
}

现在你总是通过FooBuilder来创建Foo类的实例,当你扩展Foo时,它没有任何无用的方法。

此外,我认为类中的静态方法是过程式编程的标志。静态变量只不过是包装在命名空间中伪装成类的全局变量。

【讨论】:

  • 我明白了!关于 Liskov 替代原则.. 但我怎么能把这个场景付诸实践!有什么原则遗漏了吗??有什么办法吗?
  • @TirthBodawala,你说的是哪个场景?
【解决方案2】:

您误解了 final 的含义。

OOP 的一个基本原则是,如果一个类是另一个类的子类,那么该类将获得它所继承的类的所有功能。你不能只继承一些超类功能,要么全有,要么全无。

这样做的原因有点难以理解,但一旦你这样做了,你就会意识到这是有道理的。也就是说,如果一段代码能够处理特定类的项目,那么它也必须能够处理该项目的任何子类。如果一个子类没有它的超类的所有功能,你就不能这样做。

例如,假设您有一个定义与支付网关接口的类。由于所有支付网关都不同,您不能(或至少不应该)实现一个可以与任何可用支付网关交互的类。但总的来说,支付网关以相同的基本方式工作。发送请求,包括用户的信用卡详细信息和您想从卡中扣除的金额。支付网关会回复一条消息,说明支付是否被授权。

您将使用一个抽象超类来实现这种功能,该超类定义了您与支付网关的接口方式,然后您将为您想要使用的每个支付网关(paypal、sagepay 等)创建一个子类。

由于所有这些子类都继承自同一个基类,您可以确定它们都实现了某些方法,您可以放心地向这些方法发送消息。只要您处理的支付类是抽象支付类的子类,那么一切都应该正常工作。

如果其中一个子类无法实现抽象超类中的某些内容,那么您就无法确定向子类发送特定消息是否有效,或者引发异常。这将使继承变得毫无意义。

Final 在 PHP(以及实际上实现它或类似概念的大多数 OOP 语言)中的意思是“这是此方法的最终实现。如果程序员将我子类化,那么他不能用他自己的实现替换我的最终方法” .这并不意味着这些方法在子类中不可用,只是您无法更改它们。

如果您确实必须从子类中删除功能,您可以通过覆盖超类方法并将其替换为空方法(不执行任何操作)来实现。但不要这样做,因为它会导致上述类型的问题。

一般来说,如果您遇到的情况是,您在超类中具有子类中不需要的功能,这是一种代码异味,它告诉您可能需要重新考虑您的设计。

【讨论】:

  • 谢谢哥们!这么好的解释!
【解决方案3】:

静态意味着每个类一个,而不是每个对象一个,无论可能存在多少个类的实例。这意味着您可以在不创建类实例的情况下使用它们。静态方法是隐式最终的,因为覆盖是基于对象的类型完成的,并且静态方法附加到类而不是对象。超类中的静态方法可以被子类中的另一个静态方法遮蔽,只要原始方法未声明为最终方法即可。但是,您不能用非静态方法覆盖静态方法。换句话说,您不能将静态方法更改为子类中的实例方法。

final 类不能扩展,即 final 类不能是子类。 final 方法在其类被继承时不能被覆盖。您不能更改最终变量的值(是一个常量)。

【讨论】:

    【解决方案4】:

    我同意 pomeh 关于 PHP 中 OOP 的观点,并且我还想补充一点,当与方法一起使用时,FINAL 关键字实际上意味着该方法不能被覆盖。该方法将被继承。

    【讨论】:

      【解决方案5】:

      检查这个例子:

      类 foo { 私有静态 $stuff = array('key1' => 1, 'key2' => 2); 公共最终静态函数 getstuff() { 返回自我::$东西; } }

      【讨论】:

        【解决方案6】:

        在POO中,如果一个B类继承了另一个A类,那么B类将包含A类的所有方法,这是POO继承的基础。所以I don't want that method to be inherited in the derived class 在这里毫无意义。你应该看看另一种机制来做到这一点。

        另外,在most 的情况下,这种情况(你不希望派生类继承一个方法)表明你的派生类根本不应该继承,你应该使用另一个系统。

        【讨论】:

        • 你能推荐一个吗?我使用单例结构来访问类并只初始化一次!
        • 这在很大程度上取决于你想做什么,以及你为什么想要它。
        • 我希望基类只初始化一次.. 并且派生类不拥有该 _init() 方法.. 我可以这样做吗?因为基类调用_init()静态函数时有关键数据。
        • 好吧,如果你的类是一个单例,你可以把 __init 调用放在构造函数中(如果你的 __init 函数做很多事情,这不是好方法)。或者,您可以添加一个属性,该属性将标记是否已调用 __init 方法(也不是好方法)。你到底想要什么?您是否希望 __init 方法仅被调用一次,或者您是否希望 __init 方法只能从父类中调用?第一种情况,tereško提供的方法是一种解决方案。
        • 我非常高兴你明白我的意思..我想要两个!我希望_init()函数只能被父类调用一次!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-11-09
        • 2021-05-10
        • 1970-01-01
        • 1970-01-01
        • 2012-05-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多