【问题标题】:Prevent/Restrict Method Inheritance防止/限制方法继承
【发布时间】:2012-01-12 05:39:41
【问题描述】:

我有一个应用程序,其中许多对象都扩展了一个抽象类,该类定义了create()edit()retrieve()delete() 等方法。由于每个子类对这些函数使用相同的逻辑,因此抽象类定义了默认行为,并且在需要扩充的少数情况下,子类可以覆盖或使用我内置的钩子。

现在我遇到了一些子类需要不可变的情况,这意味着它们不应该有 edit()delete() 方法。对我来说,这听起来像是一个名为immutable 之类的接口的工作,不可变类可以实现该接口。问题是接口不会阻止方法被调用,它们只是强制方法的存在。所以这显然是行不通的。

创建两个父类,一个用于可变对象,一个用于不可变对象,这很丑陋,并且可能会在维护时提出问题。我可以让不可变对象用一个什么都不做的空方法覆盖有问题的方法,但这似乎也很混乱,就像我当时没有做正确的 OOP。

那么,您认为允许大量类都继承一组方法但其中一些不继承所有方法的最佳方法是什么? (有问题的应用程序是用 php 编写的,但任何语言的通用 OOP 技术仍然有用)。

【问题讨论】:

    标签: php oop inheritance


    【解决方案1】:

    创建一个不可变基类作为基类的子类。 immutable-base 应该实现 final 覆盖 edit() 和 delete() 什么都不做或抛出错误。

    Final,这样保证所有不可变的孩子都不能编辑或删除

    这种策略的好处

    • 通过测试 instanceof immutable-base 轻松检查对象是否不可变

    • 通过修改对象的扩展内容,轻松将对象从不可变对象更改回来

    【讨论】:

    • 所以如果我理解正确,层次结构看起来像这样: Base->Immutable_Base->Immutable_Children 和 Base->Mutable_Children ?那时我会更好地将 Mutable_Base 类放在 Base 和 Mutable_Children 类之间吗?
    • 恕我直言 Mutable_Base 是不必要的,因为 Mutable 是基本情况。然而,这取决于你和你的审美。有些人非常喜欢他们的类树中的对称性。
    • 我认为这不是一个好的解决方案。如果有人调用 x.delete(y),他/她希望 y 从 x 中删除(例如,一个 Collection),而不是什么都没有发生。对我来说,问题已经在基类中,应该改变。也许只需要更改名称就足够了,请参阅stackoverflow.com/questions/2493891/…
    【解决方案2】:

    实际上创建具有空方法或抛出错误的类是不好的 - 此类方法令人困惑,它们占用空间并且什么都不做。

    更好的方法是使不可变类成为基类,并通过添加修改方法使可变类扩展它。这样每个类只有那些真正属于那里的方法。

    【讨论】:

      【解决方案3】:

      我喜欢 Java 的处理方法。抛出异常。创建一个UnsupportedOperationException,对于那些不应该使用特定方法的实现,抛出一个让用户知道他们不能在这个实现中使用这个功能。

      【讨论】:

      • 我仍然需要重写 edit()delete() 方法来抛出异常,对吧?而且我必须在每个不可变的类中都这样做,这看起来一点也不干。尽管我必须说,抛出异常确实比用空方法覆盖更有用。
      • 您必须重写该方法,但我不确定单行异常抛出是否真的违反了任何 DRY 原则。如果您只是想减少覆盖的次数,您可以简单地创建一个引发适当异常的抽象类,而您的不可变对象只需扩展它。
      【解决方案4】:

      另一个想法我想作为一个可能的解决方案抛弃。类可以实现如下所示的接口:

      Interface Immutable {
          const immutable = true;
      }
      

      然后Base抽象类可以编写delete()edit()方法

      if (!$this->immutable) {
          //do_stuff
      }
      

      这也可以很好地扩展到其他类别的分类,例如 NonDeletable 和 NonEditable 以允许更细粒度的行为。

      【讨论】:

        【解决方案5】:

        这是一个超短的解决方法,让你的方法最终并开始:

            if(self::class!=static::class) return;#or throw an error
        

        它不会阻止继承本身,但方法在子类中不起作用(有错误或没有 - 取决于你)。

        【讨论】:

          【解决方案6】:

          从 PHP 5.4 开始,您可以使用Traits

          例如,您可以创建一个仅包含所有子类具有的方法的基类:

          class EntityManager {
              public function create() {/*...*/}
              public function retrieve() {/*...*/}
          }
          

          然后你可以定义几个特征:

          trait EditTrait {
              public function edit() {/*...*/}
          }
          
          trait DeleteTrait {
              public function delete() {/*...*/}
          }
          

          然后你会像这样创建一个不可变的子类:

          class LogManager extends EntityManager {
              ...
          }
          

          还有一个像这样的可变子类:

          class ContactManager extends EntityManager {
              use EditTrait;
              use DeleteTrait;
          
              ...
          }
          

          Traits 与这里的其他一些解决方案相比具有一些优势,例如:

          • 没有重复代码。
          • 单一基类。
          • 不起作用或没有意义的方法不会出现在不支持它们的类中(对于文档和 API 尤其重要)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-12-22
            • 2011-04-15
            • 1970-01-01
            • 1970-01-01
            • 2015-12-06
            • 2010-10-31
            • 1970-01-01
            相关资源
            最近更新 更多