Class 如何处理来自两个相似子类的继承?

Class 如何处理来自两个相似子类的继承?,class,oop,inheritance,composition,traits,Class,Oop,Inheritance,Composition,Traits,我使用中的前两个视频学习了一些基本的OOP概念 最近,我主要在Node中编写,因此我在前端和后端使用原型继承。但是,这些教程展示了使用Java的OOP概念。Java是一种严格类型化的语言,它利用了经典继承 这个问题既与经典继承有关,也与原型继承有关,但方式不同 这个问题有点难以用语言表达,所以我将举一个例子: 我创建了一个名为动物的超级类。然后我创建了两个子类:马和驴。现在我的程序需要两个子类的混合。创建骡子实际上似乎有点棘手 起初,答案似乎显而易见;创建一个独立的mule子类。但这样做违背了面

我使用中的前两个视频学习了一些基本的OOP概念

最近,我主要在Node中编写,因此我在前端和后端使用原型继承。但是,这些教程展示了使用Java的OOP概念。Java是一种严格类型化的语言,它利用了经典继承

这个问题既与经典继承有关,也与原型继承有关,但方式不同

这个问题有点难以用语言表达,所以我将举一个例子:

我创建了一个名为动物的超级类。然后我创建了两个子类:马和驴。现在我的程序需要两个子类的混合。创建骡子实际上似乎有点棘手

起初,答案似乎显而易见;创建一个独立的mule子类。但这样做违背了面向对象编程的目的。当我已经有了这些特征时,创建一个新的子类是违反干燥原则的

为了确认这是创建我的mule的合适方法,我问了自己两个问题:

1) 骡子是马吗

2) 骡子是驴子吗

答案似乎是一种响亮的式的,倾向于是的

我完全不知道如何通过古典继承来实现这一点。我不能想出一个我认为是“好”的接口或抽象类解决方案

在一种像JavaScript一样使用原型继承的语言中,我可以通过只下拉应用于mule的方法和实例变量来“选择性地繁殖”mule。然而,这似乎非常接近于创建一个全新的子类


经典继承和原型继承中,处理这个问题的“正确”方法是什么?

您要寻找的概念是特征(您实际上提到了它)。我将使用另一个我认为更合适的例子:

trait Engine {
    public function startEngine() {
        echo 'Vrooom';
    }
}

trait Saddle {
    public function rideOnSaddle() {
        echo 'I feel the wind';
    }
}

interface Vehicle {
    public function go();
}

class Car extends Vehicle {
    use Engine;

    public function go() {
        echo $this->startEngine();
    }
}

class Bike extends Vehicle {
    use Saddle;

    public function go() {
        echo $this->rideOnSaddle();
    }
}

class Motorcycle extends Vehicle {
    use Engine;
    use Saddle;

    public function go() {
        echo $this->startEngine();
        echo $this->rideOnSaddle(); 
    }
}
进一步阅读:

起初,答案似乎显而易见;创建一个独立的mule子类。 但这样做违背了面向对象编程的目的。创建新的子类 当我已经有了这些特质,这就违反了干燥原则

分解可能有助于达到干燥目标

每一个不明显应该被继承的行为/角色都可能被认为是作为mixin或trait实现的。 因此,通过组合,他们在类级别的不同位置的代码重用变得更加容易和优雅

至于JavaScript,只有委托。一方面,继承受到隐式委托自动性的支持 通过原型链,而合成是通过
call
apply
明确授权功能来实现的

这使得事情变得更容易,因为只需要处理对象/实例和方法/函数对象。类/继承 JavaScript中的一部分由构造函数和每个构造函数的
原型
或者由 作为原型传递给
对象。创建
。工厂将有助于提供API并隐藏API的首选实现
这是上述方法的一部分

尽管如此,它们的核心原则仍然没有触及。。。处理a)对象和函数对象 b)继承,c)合成

因此,下面提供的示例仅选择ECMAScript-3特性和构造函数。从那里它可以 可以轻松地传输(/transpiled)到类语法或
对象。创建

OP的例子选得很好,因为骡子既不是马也不是驴。它仍然属于马驹属,但特征如下 它自身的染色体对与马或驴的染色体对不同。但它的特点是行为和可见的标记 他们两个。因此,如果有的话,继承是通过Equus实现的。其他特定的行为和外观 或者这两个物种中的每一个都会被混合成骡子

JavaScript中基于函数的mixin/traits/taliants总是应用于对象/实例,因此即使是继承的行为 通过原型链,可以收集到这样的功能,如果必要/适当,可以再次应用到原型对象

下面的示例使用了这种技术,并对其进行了评论,以演示干性和代码重用 在这两个JavaScript委托级别上

var
初始状态配置={
马匹:{
具体内容:{
类型:“马”
}/*,
仿制药:{
}*/
},
马:{
具体内容:{
类型:“马”
}/*,
仿制药:{
}*/
},
驴子:{
具体内容:{
类型:“驴子”
}/*,
仿制药:{
}*/
},
骡子:{
具体内容:{
类型:“骡子”
}/*,
仿制药:{
}*/
}
};
使用ToeltGait()函数{//基于函数的mixin/trait/talent。
this.toelt=函数(){
返回“…tölt…”;
};
归还这个;
}
函数与equal泛型(/*state*/){//基于函数的mixin/trait/talent复合。
变量
equus=这个;
//equus泛型的实现。
equalus.walk=函数(){
返回“…步行…”;
};
equus.trot=函数(){
返回“…小跑…”;
};
equus.gallop=函数(){
返回“…疾驰…”;
};
withToeltGait.call(Equals);//合成:使用/应用特定的Equals特征。
返回马匹;
}
具有相等特定项(状态)的函数{//基于函数的mixin/trait/talent。
变量
equus=th