【问题标题】:Traits vs. abstract classes for code reuse用于代码重用的特征与抽象类
【发布时间】:2016-08-23 11:44:10
【问题描述】:

在处理一个项目时,我偶然发现了一个问题,该问题与在特征与抽象基类方面选择正确的代码重用形式的正确方法有关。我遇到了这样一个问题:我有多个抽象基类,但由于 PHP 的多重继承限制,只能从一个继承。重新思考这让我质疑我的设计,所以我想知道其他人将如何解决这个问题。

以下场景

在我的项目中,我有两种计算方式

  1. 简单计算
  2. 分组计算,如果是简单的计算,只需要更多信息

设置界面

interface SimpleResultInterface{
    public function getValue();
}

interface GroupedResultInterface extends SimpleResultInterface {
    public function getGroupValues();
}

设置基类

避免代码重复是一种很好的设计形式,我设置了两个抽象基类。

abstract class SimpleResultBase implements SimpleResultInterface{

    public function getValue(){
        return 1;
    }
}

abstract class GroupedResultBase extends SimpleResultBase implements  GroupedResultInterface {

    public function getGroupValues(){
        return array(
            "group1" => 1,
            "group2" => 2,
            "group3" => 3,
        );
    }
}

所以这里的第一个问题是

  1. GroupedResultBase是否需要继承SimpleResultBase来表达SimpleResultInterfaceGroupedResultInterface的接口关系?

我选择了是,否则我将不得不从 SimpleResultBase 复制 getValue 方法

我们目前所拥有的

现在我可以eexpress了

  1. GroupedResultInterface instanceof SimpleResultInterface (true)
  2. GroupedResultBase instanceof SimpleResultBase (true)
  3. SimpleResultBase instanceof SimpleResultInterface (true)
  4. GroupedResultBase instanceof GroupedResultInterface (true)

在麻烦开始的地方具体说明

此时没有具体的类。现在我想创建两个具体的类,它们在接口定义方面有关系。

class OEESimpleResult extends SimpleResultBase {

}

class OEEGroupedResult extends GroupedResultBase{

}

这很好用,但我不能这样做

class OEESimpleResult extends SimpleResultBase {

}

class OEEGroupedResult extends OEESimpleResult,GroupedResultBase {

}

接口 GroupedResultInterface 扩展了 SimpleResultInterface

如上所述,在接口定义中。每个分组结果也是 一个简单的结果。所以我本来希望 OEEGroupedResult 也是一个 OEESimpleResult

但是当我这样做时,我不能重用我的抽象基类GroupedResultBase,因为不允许多重继承。这导致我提出以下问题。

  1. 似乎抽象类中的类关系冻结了继承链。删除抽象类并用让具体类使用它们的特征替换它们会更好吗?
  2. 如果您有多个接口但只能从一个基类继承,那么提供默认实现的正确方法是什么?
  3. 这个问题在 oop 中似乎很常见,那么是否有任何最佳实践和建议来解决这个问题?
  4. 实现接口的类是否也应该像在接口级别那样以继承的形式表达关系,还是仅靠接口关系就足够了?在我的例子中,OEEGroupedResult 应该在类级别上表达与 OEESimpleResult 的关系,就像他们在接口级别上的接口一样。

感谢您的帮助:)

【问题讨论】:

  • 您能回复一下吗,因为您的问题确实值得辩论。我的答案不是唯一的方法,所以我们可以改进它。但是,如果您当然想得到答案,则忽略它并不是最好的决定。
  • 这不是唯一的方法,但您的回答让我找到了正确的解决方案!

标签: php oop interface class-hierarchy


【解决方案1】:

当您以 oop 风格工作时,您可能听说过 SOLID 原则。 所以你的设计打破了以下字母 S、I、D 并有可能打破 O 和 L。

那么你是如何打破“S”的: 就在这里!

class OEEGroupedResult extends OEESimpleResult,GroupedResultBase {

}

突然或幸运的是 php 不允许这样做,但是您的类会提供一些额外的单独逻辑,因此您至少有两个理由来更改它。但是,是的,这是因为

interface GroupedResultInterface extends SimpleResultInterface {
    public function getGroupValues();
}

这是您的 I 字母换行符。解决方案非常简单:考虑一下您的 GroupedResultInterface 真正需要的方法并将其放入其中,真的 意味着这些方法必须完成相同的工作。它们不像你在这里打破字母 D

abstract class SimpleResultBase implements SimpleResultInterface{

    public function getValue(){
        return 1;
    }
}

abstract class GroupedResultBase extends SimpleResultBase implements  GroupedResultInterface {

    public function getGroupValues(){
        return array(
            "group1" => 1,
            "group2" => 2,
            "group3" => 3,
        );
    }
}

您的类class GroupedResultBase 依赖于另一个类的具体方法。但是你会在接口隔离后很快修复它。

通知。当我无法更改供应商类中的某些内容时,我正在使用特征。仅有的。这只是我,但当我认为这种特质会帮助我时,建筑就有问题了。当然,这取决于你。

小链接:https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)

玩得开心!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-20
    • 1970-01-01
    • 1970-01-01
    • 2020-04-21
    • 2011-01-01
    • 2011-11-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多