类 - Part II

类的知识点较多,所以分成两节进行讲解,本节是Part II,上一节是Part I


本节继续讲解类的知识点,主要包括抽象类/方法,接口,mixin以及枚举。

抽象类和抽象方法

没有函数体的方法,即只声明而不实现的方法被称为抽象方法,它只能出现在抽象类中。抽象类是使用abstract关键字修饰的类,它可以包含非抽象方法,可以被继承但不能被实例化。

  1. // 大剑抽象类
  2. abstractclassGreatSword{
  3. // 抽象方法
  4. upgrade();
  5. // 非抽象方法
  6. use(){
  7. print('attack');
  8. }
  9. }
  10. // 混种大剑继承大剑
  11. classBastardSwordextendsGreatSword{
  12. // 实现父类的抽象方法
  13. upgrade(){
  14. print('upgrade');
  15. }
  16. // 重写且使用父类已有的实现
  17. use(){
  18. super.use();
  19. }
  20. }

接口

Dart 支持接口,但没有定义接口的关键字。Dart 的每个类都隐含定义了一个接口,该接口包含当前类所有的实例变量和方法(包含通过继承和实现其他类而得来的)。通常使用抽象类来定义接口,而接口的实现是通过implements关键字,多个接口之间使用逗号分隔。

  1. // 轻攻击接口
  2. abstractclassLight{
  3. lightAttack();
  4. }
  5. // 重攻击接口
  6. abstractclassHeavy{
  7. heavyAttack();
  8. }
  9. // 大剑同时实现了轻重攻击
  10. classGreatSwordimplementsLight,Heavy{
  11. lightAttack(){
  12. print('Light attack!');
  13. }
  14. heavyAttack(){
  15. print('Heavy attack!!!');
  16. }
  17. }

mixin

mixin是一种特殊的专门用于复用的类,Dart 不直接支持多继承(子类继承多个父类),但通过mixin可以实现类似于多继承的效果。

mixin有两种书写方式,一种是使用class声明一个没有父类和构造函数的类,另一种是直接使用mixin关键字(从Dart 2.1开始引入,为了代码的明确性,笔者倾向于直接使用mixin关键字)。

在声明其他类时,使用with关键字指定一个或多个mixin,这些mixin的属性和方法就都被”混入”到当前类中,即实现了类的复用。

如果需要限定mixin只能被特定类型使用,可以使用on关键字(只适用于mixin关键字),on后跟随逗号分隔的多个父类,只有这些父类的子类才能使用当前mixin。

  1. // 使用class方式声明的轻攻击mixin
  2. classLightAttack{
  3. lightAttack(){
  4. print('Light attack!');
  5. }
  6. }
  7. // 使用mixin声明的重攻击mixin
  8. mixin HeavyAttack{
  9. heavyAttack(){
  10. print('Heavy attack!');
  11. }
  12. }
  13. // 特殊攻击方式mixin,使用on限定能够使用的类型为Weapon的子类
  14. mixin SpecialAttack on Weapon{
  15. specialAttack(){
  16. print('Special attack!');
  17. }
  18. }
  19. // 武器基类Weapon
  20. abstractclassWeapon{
  21. }
  22. // 大剑继承Weapon而且复用了LightAttack, HeavyAttack, SpecialAttack实现的方法
  23. classGreatSwordextendsWeaponwithLightAttack,HeavyAttack,SpecialAttack{
  24. attack(){
  25. lightAttack();
  26. heavyAttack();
  27. specialAttack();
  28. }
  29. }

枚举

枚举也是一种特殊的类,它专门用于表示固定数量的常量值,枚举使用关键字enum进行声明。

枚举内的值是有序的,它们的索引可以通过index属性获取,而values属性则将它们输出为一个列表(List)。

枚举不能被继承、实现和实例化,也不能被用作mixin。枚举可用于switch语句和for...in循环。

  1. // 方向枚举:东南西北
  2. enumDirection{ north, east, south, west }
  3. printDirection(){
  4. // 通过for...in遍历values列表并打印所有方向的索引
  5. for(Direction direction inDirection.values){
  6. print(direction.index);
  7. }
  8. }