Dart的语法详解系列篇(三)-- mixin入门详解一、继承歧义

版权声明:本文为博主原创文章,未经博主允许不得转载。https://www.jianshu.com/p/405ba04

在面向对象的编程语言中,Mixin是包含供其他类使用的方法的类,而不必是其他类的父类。其他类如何访问Mixin的方法取决于语言。Mixin有时被描述为“包含的”而不是“继承的”。

Mixins鼓励代码重用,并且可用于避免多重继承可能导致的继承歧义(菱形问题),或者用于解决语言中缺少对多重继承的支持的问题。Mixin还可以被视为具有实现方法的接口。这个模式是执行依赖倒置原则的一个例子。

一、继承歧义

(一)定义

继承歧义,也叫菱形问题,也叫做钻石问题,或者有时被称为致命的死亡钻石。当两个B和C类继承自A,D类继承自B和C时产生歧义。如果A中有一个方法在B和C中已经重写,而D没有重写它,那么D继承的方法的版本是B,还是C?

如下图所示:

钻石问题示意图

(二)继承歧义的缓解

不同的编程语言有不同的方法来处理这些重复继承的问题,这里列举几个用的比较多的语言。

语言

解决方案

C++(底层、硬件、编解码、算法等都用得到)

默认情况下,每个继承路径都是分开的,因此D对象实际上包含两个独立的a对象,并且必须正确限定a成员的使用。如果从A到B的继承和从A到C的继承都标记为virtual(例如,class B:virtual public A),那么c++会特别注意只创建一个对象,并正确使用A的成员。如果虚拟继承和非虚拟继承是混合的,那么只有一个虚拟A,对于每个到A的非虚拟继承路径,都有一个非虚拟A。C++需要显式地声明要使用的特性是从哪个父类调用的(例如:Worker::Human.Age)。C++不支持显式的重复继承,因为没有办法限定要使用哪个超类(例如:在一个派生列表[class Dog : public Animal, Animal]中出现一个类不止一次)。C++还允许通过虚拟继承机制创建多个类的单个实例(例如:Worker::Human和Musician::Human将引用相同的对象)。

Java8(服务端开发、Android开发)

Java 8在接口上引入默认方法。如果A、B、C是接口,B、C可以为A的抽象方法提供不同的实现,从而导致菱形问题。D类必须重新实现该方法(它的主体可以简单地将调用转发给一个超类来实现),否则模糊将被拒绝作为编译错误。(在Java 8之前,Java不受钻石问题风险的影响,因为它不支持多重继承。)

Go(可以用于区块链有关)

在编译时防止钻石问题。如果一个结构体D嵌入两种结构体B和C(这两个结构体都有一个方法F()),从而满足接口A,那么如果调用D.F(),或者如果D的实例被分配给类型A.B和C的变量,则编译器将会提示ambiguous selector(模拟两可的选择)。

Python(可以用于人工智能有关)

Python的继承顺序影响类语义。Python在引入新样式的类时必须处理这个问题,所有这些类都有一个共同的祖先对象。Python使用C3线性化(或方法解析顺序(Method Resolution Order,MRO))算法创建类列表。该算法强制执行两个约束:子类先于父类,如果一个类从多个类继承,它们将按照基类元组中指定的顺序保存(但是在这种情况下,继承图中较高的一些类可能先于图中较低的类)。因此,方法的分辨率顺序为:D, B, C, A。

Scala(可以用于大数据方面)

Scala允许特性的多个实例化,通过在类层次结构和特征层次结构之间添加区别,可以实现多重继承。类只能从单个类继承,但是可以根据需要混合(mix-in)任意多的特性。Scala使用扩展的traits的右优先深度优先的搜索来解析方法名,然后除去结果列表中每个模块的最后一次出现。所以,解决的顺序是[D, C, A, B, A],被减少到[D, C, B, A]

只允许单个继承(类只能从一个基类派生)的语言没有菱形问题。这样做的原因是,无论方法的重复或位置如何,这些语言在继承链的任何级别上最多只能实现一个方法。通常,这些语言允许类实现多个protocols,在Java中称为接口。这些协议定义了方法,但没有提供具体的实现。这个策略已经被ActionScript、c#、D、Java、Nemerle、Object Pascal (Free Pascal and Delphi)、Objective-C、Smalltalk、Swift、PHP所使用。所有这些语言都允许类实现多个protocols

此外,Ada、Objective-C、c#、Delphi/Free Pascal、Java、Swift、PHP等语言允许接口的多重继承(在Objective-C和Swift中称为protocols(协议))。接口就像抽象基类,它们指定方法签名而不实现任何行为。(“纯”接口,例如版本7之前的Java接口,不允许接口中的任何实现或实例数据。)然而,即使当多个接口声明相同的方法签名时,只要该方法在继承链中的任何位置实现(定义),它就会覆盖该方法在其上链中的任何实现(在它的超类中)。因此,在继承链的任何给定级别上,任何方法最多只能有一个实现。因此,单继承方法实现即使在接口的多继承中也不存在菱形问题。随着Java 8中接口的默认实现的引入,仍然有可能生成菱形问题,尽管这只会作为编译时错误出现。


本文转载自:https://en.wikipedia.org/wiki/Mixin#Programming_languages_that_use_mixins

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券