java mixin_理解Dart的Mixin继承机制

2019独角兽企业重金招聘Python工程师标准>>>

6936d1565ae689371725cdb5fc51c415.png

Dart语言集合了现代编程语言的众多优点,Mixin继承机制也是其一。但针对Java程序员来说,可能不是一下子能理解的,比如我第一次看到的时候,也迷迷糊糊了半天——这是啥玩意???

要说Mixin,可能写成MixIn会更好理解,翻译回来就是混入,当然你执意说这是一种“迷信”继承机制,那也没辙。

下面将从一个实际情景入手,对比Java和Dart的实现,以便更好理解Dart的mixin。

场景

我们先来描绘这么一个职业关系图:

a88ca4ddf3848f4575f9efe744420be6.png

职业关系图

从图中可以梳理出以下关系:

工程师类目,有软件工程师和建筑工程师师等,他们共同点都是工程师

教师类目有美术教师,IT教师等,他们共同点都是教师

而以上的工程师、教师都是社会的工作者。

那么接下来我们分别使用Java和Dart来实现这个关系类。

注意:接下来的这篇文章中为了方便表达意义,将所有类写在一个文件里面,请暂时忽略代码不规范细节。并且Dart在本文不会使用语法糖写法。

Java版本实现

从层级出发,可以写出Java版本实现如下:

//工作者

abstract class Worker {

public abstract void doWork();//工作者需要工作

}

//工程师

class Engineer extends Worker {

@Override

public void doWork() {

System.out.println("工程师在工作");

}

}

//教师

class Teacher extends Worker {

@Override

public void doWork() {

System.out.println("教师在教学");

}

}

//软件工程师

class SoftwareEngineer extends Engineer {

}

//建筑工程师

class BuildingEngineer extends Engineer {

}

//美术教师

class ArtTeacher extends Teacher {

}

//IT教师

class ITTeacher extends Teacher {

}

Dart版本实现

//工作者

abstract class Worker {

void doWork();//工作者需要工作

}

//工程师

class Engineer extends Worker {

void doWork() {

print('工程师在工作');

}

}

//教师

class Teacher extends Worker {

void doWork() {

print('教师在教学');

}

}

//软件工程师

class SoftwareEngineer extends Engineer {

}

//建筑工程师

class BuildingEngineer extends Engineer {

}

//美术教师

class ArtTeacher extends Teacher {

}

//IT教师

class ITTeacher extends Teacher {

}

从上面实现可以看出,两个实现并没什么卵区别好咩。。。。。。

嗯,目前来说确实是这样的,因为Dart也是单继承。

因为上面的场景是在是too young too simple了,下面开始扩展一些场景。

场景扩展

还是刚刚那张关系图,我们开始思考这些职业他们都具有什么能力。

于是我给这些职业虚拟了以下能力:

职业

能力

软件工程师

软件设计、修电脑

建筑工程师

手绘

美术教师

手绘、书法

IT教师

修电脑

他们的关系图如下:

6c015a0fae1d5a5bf694dcfc9ddbc8ad.png

通过图形或表格可以看出,软件工程师和IT教师都具备修电脑的能力,建筑工程师和美术教师都具备手绘的能力,但是这些能力都是他们特有的,不是工程师或者教师具备的能力,所以不能在他们的父类中实现。

那么这个时候我们就考虑到一个东西——接口。

以软件工程师和IT教师为例:

他们都具备修电脑的能力:

interface CanFixComputer {

void fixComputer();

}

interface CanDesignSoftware {

void designSoftware();

}

//软件工程师

class SoftwareEngineer extends Engineer implements CanFixComputer, CanDesignSoftware {

@Override

public void fixComputer() {

System.out.println("修电脑");

}

@Override

public void designSoftware() {

System.out.println("设计软件");

}

}

//IT教师

class ITTeacher extends Teacher implements CanFixComputer {

@Override

public void fixComputer() {

System.out.println("修电脑");

}

}

相当标准的实现了

我们知道Dart是没有interface这种东西的,但并不以为着这门语言没有接口,事实上,Dart任何一个类都是接口,你可以实现任何一个类,只需要重写那个类里面的所有具体方法。

我们只需要将上面的interface 修改成 abstract class,就是dart中的实现了。

但是我们发现,fixComputer这个接口被继承了两次,并且两次的实现都是一样的,这里就出现了代码重复和冗余的问题。怎么办呢?在java中我们有接口的default实现来解决这个问题(这是一个java8出现的不得已的方案。)

这个时候mixin的作用就出现了

abstract class CanFixComputer {

void fixComputer() {

print('修电脑');

}

}

abstract class CanDesignSoftware {

void designSoftware() {

print('设计软件');

}

}

//软件工程师

class SoftwareEngineer extends Engineer

with CanFixComputer, CanDesignSoftware {

}

//IT教师

class ITTeacher extends Teacher with CanFixComputer {

}

main() {

ITTeacher itTeacher = new ITTeacher();

itTeacher.doWork();

itTeacher.fixComputer();

SoftwareEngineer softwareEngineer = new SoftwareEngineer();

softwareEngineer.doWork();

softwareEngineer.fixComputer();

softwareEngineer.designSoftware();

}

可以看到,这里不再用implements,更不是extends,而是with。

而且,每个具有某项特性的类不再需要具体去实现同样的功能,接口是没法实现功能的,而通过继承的方式虽然能实现功能,但已经有父类,同时不是一个父类,又不能多继承,所以这个时候,Dart的Mixin机制就比Java的接口会高效,开发上层的只需要关心当前需要什么特性,而开发功能模块的关心具体要实现什么功能。

顺序的理解

既然是with,那应该也会有顺序的区别,

思考一个问题:如果同时with两个类,但两个类中有同样的一个方法的不同实现,那么这个时候应该使用的是哪一个类的方法?

下面以一个简单的Demo来说明这个问题:

class First {

void doPrint() {

print('First');

}

}

class Second {

void doPrint() {

print('Second');

}

}

class Father {

void doPrint() {

print('Father');

}

}

class Son1 extends Father with First,Second {

void doPrint() {

print('Son1');

}

}

class Son2 extends Father with First implements Second {

void doPrint() {

print('Son2');

}

}

main() {

Son1 son1 = new Son1();

son1.doPrint();

Son2 son2 = new Son2();

son2.doPrint();

}

那么这个程序运行后,将会在控制台输出如下:

1

2

Son1

Son2

可以看到,无论是extends、implements还是mixin,优先级最高的是在具体类中的方法。

我们稍微改一下上面的例子:

class First {

void doPrint() {

print('First');

}

}

class Second {

void doPrint() {

print('Second');

}

}

class Father {

void doPrint() {

print('Father');

}

}

class Son1 extends Father with First,Second {

}

class Son2 extends Father with First implements Second {

}

main() {

Son1 son1 = new Son1();

son1.doPrint();

Son2 son2 = new Son2();

son2.doPrint();

}

这个时候控制台输出如下:

1

2

Second

First

可以看到,其实在Son2中implements只是说要实现他的doPrint()方法,这个时候其实具体实现是First中Mixin了具体实现。

而Mixin的具体顺序也是可以从代码倒过来看的,最后mixin的优先级是最高的。

PS: dart中有个关键字 mixin 可以用来替换上面的 class,这个类表示专门用来做mixin的。

另外在mixin类中我们还以使用这样使用

mixin MusicalPerformer on Musician {

// ···

}

这个表示只有类Musician能够使用这个mixin类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值