Dart之抽象类、混入

Dart之抽象类、混入思维导图

一、前言

在前面学习继承和多态时,我们知道子类可以继承父类,也可以重写父类方法。

但实际开发里还会遇到两个问题:

第一,有些父类只是用来规定能力,并不希望直接创建对象。比如“动物”这个概念可以作为抽象分类,但真正运行时通常是猫、狗、鸟这些具体对象。

第二,有些能力并不适合放进单一继承关系里。比如“会飞”“会游泳”“会记录日志”这些能力,可能很多不同类都需要,但它们之间未必有父子关系。

这就引出了 Dart 中两个重要概念:抽象类和混入。

二、一句话理解

抽象类用于定义一类对象应该具备的共同规则,混入用于把一组可复用能力灵活添加到类中。

简单说:

  • 抽象类:规定“你应该有什么能力”。
  • 抽象方法:只声明,不实现,让子类去完成。
  • 混入:把一组能力插到类里复用。
  • 继承:表达“是什么”。
  • 混入:表达“能做什么”。

三、抽象类

3.1 什么是抽象类

抽象类使用 abstract 修饰。

它通常用于描述一类对象的共同规则,但不一定直接创建对象。

abstract class Animal {
  void eat();
}

这里 Animal 是抽象类,eat() 是抽象方法。

抽象方法没有方法体,它只规定子类必须具备这个能力。

3.2 抽象类不能直接实例化

抽象类不能直接创建对象。

abstract class Animal {
  void eat();
}

void main() {
  // Animal animal = Animal(); // 错误
}

原因很简单:抽象类可能有未实现的方法,直接创建对象没有意义。

3.3 子类实现抽象方法

子类继承抽象类后,需要实现抽象方法。

abstract class Animal {
  void eat();
}

class Dog extends Animal {
  @override
  void eat() {
    print('dog eat');
  }
}

void main() {
  Dog dog = Dog();
  dog.eat();
}

这里 Dog 继承 Animal,并实现了 eat()

3.4 抽象类可以有普通方法

抽象类不只能写抽象方法,也可以写已经实现好的普通方法。

abstract class Animal {
  void eat();

  void sleep() {
    print('animal sleep');
  }
}

class Cat extends Animal {
  @override
  void eat() {
    print('cat eat');
  }
}

void main() {
  Cat cat = Cat();
  cat.eat();
  cat.sleep();
}

这意味着抽象类既可以规定规则,也可以提供公共实现。

3.5 抽象类适合什么场景

抽象类适合这些场景:

  • 多个子类有共同能力。
  • 需要强制子类实现某些方法。
  • 父类本身不应该被直接实例化。
  • 需要在父类中提供一部分公共实现。

例如支付系统:

abstract class Payment {
  void pay(double amount);

  void printReceipt() {
    print('print receipt');
  }
}

class WeChatPay extends Payment {
  @override
  void pay(double amount) {
    print('wechat pay $amount');
  }
}

class AliPay extends Payment {
  @override
  void pay(double amount) {
    print('alipay pay $amount');
  }
}

Payment 规定支付能力,具体支付方式由子类实现。

四、混入 mixin

4.1 什么是 mixin

mixin 用于定义一组可以复用的能力。

mixin Logger {
  void log(String message) {
    print('log: $message');
  }
}

它不像普通父类那样强调“是什么”,更强调“能做什么”。

4.2 使用 with 混入能力

类可以通过 with 使用 mixin。

mixin Logger {
  void log(String message) {
    print('log: $message');
  }
}

class UserService with Logger {
  void getUser() {
    log('get user');
  }
}

void main() {
  UserService service = UserService();
  service.getUser();
}

UserService 不是 Logger 的子类,但它获得了 Logger 里的 log() 能力。

4.3 一个类可以混入多个 mixin

Dart 是单继承语言,一个类只能继承一个父类。

但一个类可以混入多个 mixin。

mixin Logger {
  void log(String message) {
    print('log: $message');
  }
}

mixin Cache {
  void saveCache(String key) {
    print('save cache: $key');
  }
}

class DataService with Logger, Cache {
  void loadData() {
    log('load data');
    saveCache('user_list');
  }
}

这就是 mixin 的灵活之处:它能横向复用能力。

4.4 mixin 的 on 限制

有些 mixin 只能用于特定父类或特定类型。

可以使用 on 限制。

class Animal {
  String name;

  Animal(this.name);
}

mixin Run on Animal {
  void run() {
    print('$name is running');
  }
}

class Dog extends Animal with Run {
  Dog(super.name);
}

Run on Animal 表示这个 mixin 只能混入到 Animal 或其子类中。

这样 mixin 内部就可以安全使用 Animal 的成员,比如 name

4.5 mixin 中的方法冲突

如果多个 mixin 中有同名方法,后面的 mixin 会覆盖前面的同名方法。

mixin A {
  void hello() {
    print('A');
  }
}

mixin B {
  void hello() {
    print('B');
  }
}

class Demo with A, B {}

void main() {
  Demo demo = Demo();
  demo.hello(); // B
}

所以使用多个 mixin 时,要注意方法命名和混入顺序。

五、抽象类和 mixin 的区别

抽象类和 mixin 都能复用代码,但它们表达的关系不一样。

对比 抽象类 mixin
关注点 规定一类对象的共同规则 复用一组能力
使用方式 extends with
关系含义 是什么 能做什么
数量限制 单继承 可多个混入
是否可有实现 可以 可以
常见用途 定义基类、模板、规范 横向复用能力

举个例子:

  • Dog extends Animal:狗是动物。
  • Dog with Run:狗具备跑的能力。

如果表达“某类对象的本质分类”,优先考虑抽象类。

如果表达“多个不同类都能复用的能力”,优先考虑 mixin。

六、常见误区

6.1 把抽象类当普通类用

抽象类不能直接实例化。

它更像规范或模板,而不是具体对象。

6.2 所有复用都用继承

继承是强关系,表示 “is-a”。

如果只是多个类都需要同一组能力,mixin 往往更灵活。

6.3 mixin 里随便依赖外部字段

如果 mixin 中要使用某个父类成员,应该考虑用 on 限制类型。

否则混入到不合适的类中,代码会变得不安全、不清楚。

6.4 忽略多个 mixin 的顺序

多个 mixin 有同名方法时,后面的会覆盖前面的。

class Demo with A, B {}

这里 B 的同名方法优先级更高。

七、总结

这一篇我们系统讲了 Dart 中的抽象类和混入。

抽象类用于定义共同规则。它可以包含抽象方法,也可以包含普通方法,但不能直接实例化。子类继承抽象类后,需要实现抽象方法。

mixin 用于复用一组能力。类可以通过 with 混入一个或多个 mixin,也可以使用 on 限制 mixin 只能用于特定类型。

最后记住这组区别:

  • 抽象类强调“是什么”。
  • mixin 强调“能做什么”。
  • 继承适合纵向分类。
  • mixin 适合横向能力复用。
posted @ 2026-08-12 22:10  好的佩奇  阅读(13)  评论(0)    收藏  举报