在使用Java
语言设计类之间关系的时候,咱们会接触到 组成单元 和 关系链接 这两类概念:html
abstract
抽象类,interface
接口。implements
实现,extends
继承。而在Dart
当中,对于这两类概念进行了增减:函数
abstract
抽象类、mixin
。implements
实现、extends
继承、with
混入。最大的不一样有两点:post
interface
。下面咱们就来看一下其中涉及到的知识点,前面两节对比一下Java
和Dart
的区别,最后着重介绍混入的概念。学习
推荐给你们一个网站:dartpad.dartlang.org/ 能够在线运行。网站
Java
和Dart
的普通类有区别,可是不影响咱们设计类之间的关系,所以再也不赘述。ui
Java
和Dart
的抽象类定义时大致是同样的,咱们能够在其中定义变量、普通方法、抽象方法,它和普通类最大的区别就是 抽象类不能实例化。spa
Java
和Dart
在使用抽象类时有一点不一样:Dart
在定义抽象方法时,不须要用abstract
修饰。设计
abstract class DartAbs {
void absMethod();
}
复制代码
在Dart
中,没有 interface 关键字。code
顺带咱们复习一下Java
中abstract
和interface
的一些要点:htm
Java
和Dart
中extends
是一致的,只能够单继承,要注意的点是:
Java
来讲,可见指的是非private
修饰,Dart
来讲,指的是非下划线_
开头。super
关键字。class Extends {
void base() {
print('base');
}
void log() {
print('extends');
}
}
class Log extends Extends {
log() {
print('log');
}
}
void main() {
Log().base();
Log().log();
}
复制代码
输出结果:
base
log
复制代码
implements
与extends
最大的不一样就是容许后面接上多个普通或者抽象类,当咱们使用B implement A
修饰时,那么A
中的全部的属性和方法都要在A
中实现,不管它原来是抽象方法仍是普通方法。
也就是说若是咱们只想要A
中的接口定义,而不想要它的实现,那么就试用implements
。
class Implements {
void base() {
print('base');
}
void log() {
print('extends');
}
}
class Log implements Implements {
base() {
print('log#base');
}
log() {
print('log');
}
}
void main() {
Log().base();
Log().log();
}
复制代码
输出结果:
log#base
log
复制代码
前面咱们介绍的都是Java
中接触过的概念,下面咱们来介绍Dart
中特有的概念 - 混入。
mixin
用于修饰类,和abstract
相似,该类能够拥有成员变量、普通方法、抽象方法,可是不能够实例化。mixin
通常用于描述一种具备某种功能的组块,而某一对象能够拥有多个不一样功能的组块。
最简单的mixin
由mixin & with
关键字组成。
举个例子,咱们有一种能力是 '绘画',而拥有这种能力的是 ‘教师’,那么实现以下:
mixin DrawFunc {
String content = '..';
String what();
void draw() {
print('I can draw ${what()}');
}
}
class Teacher with DrawFunc {
String what() => "car";
}
void main() {
Teacher().draw();
}
复制代码
咱们限定了 '绘画' 这种能力只可以用在 '人类' 上面,示例以下:
class Person {}
mixin DrawFunc on Person {
String content = '..';
String what();
void draw() {
print('I can draw ${what()}');
}
}
class Teacher extends Person with DrawFunc {
String what() => "car";
}
void main() {
Teacher().draw();
}
复制代码
当咱们在mixin
上使用了on
关键字,那么mixin
只能在那个类的子类上使用,而mixin
能够调用那个类的方法。
在 '绘画' 的基础上,咱们增长一种新的能力 '唱歌',示例以下:
class Person {}
mixin DrawFunc on Person {
String content = '..';
String what();
void draw() {
print('I can draw ${what()}');
}
}
mixin SingFunc on Person {
void sing() {
print('I can sing');
}
}
class Teacher extends Person with DrawFunc, SingFunc {
String what() => "car";
}
void main() {
Teacher().draw();
Teacher().sing();
}
复制代码
关于on
还有一种复杂的变形,咱们在 '唱歌' 上增长一条约束,要求它必须是在DrawFunc
之上:
mixin SingFunc on Person, DrawFunc {
void sing() {
print('I can sing');
}
}
复制代码
那么这时候,虽然Teacher
没有extends DrawFunc
,可是以下的代码仍然能够编译经过:
class Teacher extends Person with DrawFunc, SingFunc {
String what() => "car";
}
复制代码
而咱们交换一下DrawFunc
和SingFunc
的顺序就不行了:
class Teacher extends Person with SingFunc, DrawFunc {
String what() => "car";
}
复制代码
提示信息是:
Error compiling to JavaScript:
main.dart:22:7:
Error: 'Person' doesn't implement 'DrawFunc' so it can't be used with 'SingFunc'.
- 'Person' is from 'main.dart'.
- 'DrawFunc' is from 'main.dart'.
- 'SingFunc' is from 'main.dart'.
class Teacher extends Person with SingFunc, DrawFunc {
^
Error: Compilation failed.
复制代码
结论:要知足
on
的要求,除了使用extends
以外,还能够在with
列表中,在它以前进行声明。在Flutter
的WidgetsFlutterBinding
中,就涉及到了这一点的运用。
abstract class BindingBase {}
mixin ServicesBinding on BindingBase {}
mixin SchedulerBinding on BindingBase, ServicesBinding {}
mixin RendererBinding on BindingBase, ServicesBinding {}
class WidgetsFlutterBinding extends BindingBase with ServicesBinding, SchedulerBinding, RendererBinding {}
复制代码
在这上面,咱们接触了几个新的概念mixin, on, with
:
mixin
:定义了组块。on
:限定了使用mixin
组块的宿主必需要继承于某个特定的类;在mixin
中能够访问到该特定类的成员和方法。with
:负责组合组块,而with
后面跟的类并不必定须要是mixin
的,abstract class
和普通类都是能够的,这一点须要注意,例以下面这样:class Person {}
mixin DrawFunc on Person {
String content = '..';
String what();
void draw() {
print('I can draw ${what()}');
}
}
mixin SingFunc on Person {
void sing() {
print('I can sing');
}
}
abstract class DanceFunc {
void dance() {
print('I can dance');
}
}
class Teacher extends Person with DrawFunc, SingFunc, DanceFunc {
String what() => "car";
}
void main() {
Teacher().draw();
Teacher().sing();
Teacher().dance();
}
复制代码
若是同时存在extends, with
,而且它们都定义了相同的方法名,那么结果如何呢?咱们来看下面的例子:
class Extends {
void log() {
print('extends');
}
}
mixin Mixins {
void log() {
print('mixin');
}
}
mixin Mixins2 {
void log() {
print('mixin2');
}
}
class Log extends Extends with Mixins, Mixins2 {}
void main() {
Log().log();
}
复制代码
输出结果:
mixin2
复制代码
结论
with
修饰的会覆盖extends
中修饰的同名方法。with
列表中后一个的会覆盖以前的。再来看一下加上了implements
的状况。
class Extends {
void log() {
print('extends');
}
}
mixin Mixins {
void log() {
print('mixin');
}
}
mixin Mixins2 {
void log() {
print('mixin2');
}
}
class Implements {
void log() {
print('implements');
}
}
class Log extends Extends with Mixins, Mixins2 implements Implements {}
void main() {
Log().log();
}
复制代码
输出结果为:
mixin2
复制代码
这里咱们发现了一个奇怪的现象:虽然咱们加上了implements
,可是Dart
竟然没让咱们实现Implements.log()
方法!
这是由于在这种状况下,它识别到咱们从with
和extends
中得到了log()
方法的能力,所以调用的是Mixins2.log()
。
假如咱们对Implements#log
方法进行实现:
class Log extends Extends with Mixins, Mixins2 implements Implements {
void log() {
print("implements log");
}
}
复制代码
输出的结果为:
implements log
复制代码
梳理下来,有几点感想:
interface
的部分,能够采用只带有抽象方法的abstract class
替换,并继续使用implements
关键字。mixin
的概念,我是将它理解为一个个的功能组块:哪些宿主须要哪些功能,我就with
到上去。on
关键字一方面是为了限制组块的应用场景,也能够为多个组块提供公共的基础功能。