代码重用的特征与抽象 类

Traits vs. abstract classes for code reuse

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

以下场景

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

  1. 简单计算
  2. 分组计算,以防万一是简单的计算,只是包含更多信息

设置接口

interface SimpleResultInterface{
    public function getValue();
}

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

设置基础classes

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

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. GroupedResultBaseSimpleResultInterface表达接口关系是否需要继承SimpleResultBaseGroupedResultInterface ?

我选择了是,否则我将不得不从 SimpleResultBase

复制 getValue 方法

我们目前有什么

现在我可以 epxpress

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

在问题开始的地方具体化

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

class OEESimpleResult extends SimpleResultBase {

}

class OEEGroupedResult extends GroupedResultBase{

}

这很好用,但我做不到的是这个

class OEESimpleResult extends SimpleResultBase {

}

class OEEGroupedResult extends OEESimpleResult,GroupedResultBase {

}

interface GroupedResultInterface extends SimpleResultInterface

As above noted in the interface definiton. Each grouped result is also a simple result. So i would have expected that OEEGroupedResult also is a OEESimpleResult

但是当我这样做时,我不能重用我的抽象基础 class GroupedResultBase 因为不允许多重继承。这让我想到了以下问题。

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

谢谢你的帮助:)

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

那你是怎么破解的"S": 就在这里!

class OEEGroupedResult extends OEESimpleResult,GroupedResultBase {

}

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

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

这是你的 I 字母中断。解决方案非常简单:考虑您的 GroupedResultInterface 真正需要的方法并将其放入其中 really 意味着这些方法必须完成相同的工作。他们不像你在这里打破字母 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,
        );
    }
}

你的classclass GroupedResultBase取决于另一个class的具体方法。但是你会在接口隔离之后很快修复它。

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

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

玩得开心!