【Dart 语言学习教程 】 第二章:面向对象编程

本章深入 Dart 的面向对象特性,涵盖类与对象、构造函数、私有成员、继承、抽象类、混入、枚举等核心概念。每个知识点配有完整代码示例和详细解析,帮助掌握 Dart 独特的 OOP 风格。


2.1 类与对象

知识点

  • 类的定义 :使用 class 关键字
  • 成员变量:实例变量(可设置初始值)
  • 成员方法:定义对象行为
  • 对象创建new 关键字可选,通常省略
  • this 关键字:指向当前实例,用于区分参数和成员变量

代码示例

dart 复制代码
void main() {
  // 创建对象
  var person = Person('Alice', 25);
  person.sayHello();

  // 修改属性
  person.age = 26;
  person.sayHello();
}

class Person {
  // 成员变量
  String name;
  int age;

  // 构造函数
  Person(this.name, this.age);

  // 成员方法
  void sayHello() {
    print('Hello, I am $name, $age years old.');
  }
}

解析

  • Person(this.name, this.age) 是 Dart 的语法糖,自动将参数赋值给同名成员变量。
  • 实例变量默认是 public,没有 public / private 关键字(使用 _ 前缀实现私有)。
  • Dart 中所有对象都继承自 Object 类。

2.2 构造函数

知识点

  • 默认构造函数:与类同名,无参数
  • 命名构造函数类名.名称(),用于多种构造方式
  • 初始化列表:构造函数体执行前初始化成员变量
  • 常量构造函数const 关键字,用于创建编译时常量对象
  • 工厂构造函数factory,用于控制实例的返回(如单例、缓存)

代码示例

dart 复制代码
void main() {
  // 普通构造
  var p1 = Point(1, 2);

  // 命名构造
  var origin = Point.origin();

  // 常量构造
  const immutable = ImmutablePoint(3, 4);

  // 工厂构造(单例)
  var instance1 = Logger('main');
  var instance2 = Logger('main');
  print(identical(instance1, instance2)); // true(相同实例)
}

class Point {
  double x, y;
  // 普通构造函数 + 初始化列表
  Point(this.x, this.y);

  // 命名构造函数
  Point.origin() : x = 0, y = 0;

  // 重定向构造函数(调用另一个构造函数)
  Point.fromJson(Map<String, double> json) : this(json['x']!, json['y']!);
}

class ImmutablePoint {
  final double x, y;
  // 常量构造函数(所有成员必须 final)
  const ImmutablePoint(this.x, this.y);
}

class Logger {
  final String name;
  static final Map<String, Logger> _cache = {};

  // 工厂构造函数:返回缓存实例
  factory Logger(String name) {
    return _cache.putIfAbsent(name, () => Logger._internal(name));
  }

  // 私有命名构造,供工厂使用
  Logger._internal(this.name);
}

解析

  • 初始化列表在构造函数体之前执行,适合初始化 final 变量。
  • 常量构造函数必须用 const 调用,可放在常量上下文中,Flutter 中能提升性能。
  • 工厂构造函数不创建新实例,可以返回已有对象或子类型。

2.3 私有成员

知识点

  • 私有性 :使用 _ 前缀标识符为库私有
  • 范围 :私有成员只能在当前 .dart 文件内访问(库级别)
  • Getter / Setter:提供对私有字段的受控访问

代码示例

dart 复制代码
void main() {
  var bank = BankAccount('12345');
  bank.deposit(100);
  print(bank.balance); // 100
  // bank._balance = 500;  // 错误:私有成员不可访问
  // bank._validate();      // 错误
}

class BankAccount {
  String accountId;
  double _balance;        // 私有变量

  BankAccount(this.accountId) : _balance = 0;

  // Getter
  double get balance => _balance;

  // Setter(示例,通常不直接暴露 setter)
  set balance(double value) {
    if (value >= 0) _balance = value;
  }

  void deposit(double amount) {
    if (amount > 0) {
      _balance += amount;
      _validate();
    }
  }

  void _validate() {      // 私有方法
    if (_balance < 0) throw Exception('Negative balance');
  }
}

解析

  • Dart 没有 private 关键字,以 _ 开头即表示私有。
  • 私有成员仍可通过反射访问,但不推荐。
  • Getter 和 Setter 看起来像普通属性,但实际是方法调用。

2.4 Getter / Setter

知识点

  • 计算属性 :通过 get 关键字定义没有存储空间的值
  • 自定义 Setter :通过 set 关键字拦截赋值
  • 使用方式 :像普通字段一样使用 . 访问

代码示例

dart 复制代码
void main() {
  var rect = Rectangle(3, 4);
  print(rect.area);       // 12(计算属性)
  rect.area = 20;         // 调用 setter,修改宽高
  print(rect.width);      // 4.0
  print(rect.height);     // 5.0
}

class Rectangle {
  double width, height;

  Rectangle(this.width, this.height);

  // Getter
  double get area => width * height;

  // Setter:设置面积时按比例调整宽高
  set area(double value) {
    var ratio = width / height;
    width = (value * ratio).sqrt();
    height = width / ratio;
  }
}

解析

  • Getter 没有参数,必须有返回值。
  • Setter 只能有一个参数,没有返回值。
  • 实际开发中常使用 Getter 暴露私有字段的只读版本。

2.5 继承

知识点

  • extends:单继承一个父类
  • @override:标注重写父类方法(可选但推荐)
  • super:调用父类的构造函数或方法
  • 方法重写:子类可以改变父类行为

代码示例

dart 复制代码
void main() {
  var dog = Dog('Buddy');
  dog.speak();    // Buddy says Woof!
  dog.eat();      // Buddy is eating.

  var animal = Animal('Generic');
  animal.speak(); // Generic makes sound.
}

class Animal {
  String name;
  Animal(this.name);

  void speak() {
    print('$name makes sound.');
  }

  void eat() {
    print('$name is eating.');
  }
}

class Dog extends Animal {
  Dog(String name) : super(name);

  @override
  void speak() {
    print('$name says Woof!');
  }

  // 可以选择不重写 eat,直接继承
}

解析

  • 子类构造函数必须调用父类构造函数(默认调用无参构造,有参需手动 super(...))。
  • @override 不是必需的,但有助于编译器检查和代码可读性。
  • Dart 不支持多继承(但可以通过混入实现类似效果)。

2.6 抽象类与接口

知识点

  • 抽象类abstract 关键字,不能实例化,可包含抽象方法(无方法体)
  • 接口 :每个类都隐含是一个接口,使用 implements 实现多个接口
  • 区别extends 继承实现;implements 只继承接口签名,必须重新实现所有方法

代码示例

dart 复制代码
void main() {
  // Animal a = Animal(); // 错误:抽象类不能实例化
  Dog dog = Dog();
  dog.speak();
  dog.run();

  // 使用接口实现
  Robot robot = Robot();
  robot.move();
}

abstract class Animal {
  void speak();   // 抽象方法,无方法体
  void breathe() {
    print('Breathing');
  }
}

class Dog implements Animal {
  // 必须实现所有抽象方法
  @override
  void speak() => print('Woof!');

  // 即使父类有实现,implements 后也要重新实现
  @override
  void breathe() => print('Dog breathing');

  void run() => print('Running');
}

// 接口示例:定义一个移动接口
abstract class Movable {
  void move();
}

class Robot implements Movable {
  @override
  void move() => print('Robot moving');
}

解析

  • 抽象类可以包含具体方法,子类通过 extends 继承。
  • 一个类可以 implements 多个接口,用逗号分隔。
  • 推荐使用 abstract class 定义纯接口,或使用 mixin

2.7 混入(Mixin)

知识点

  • mixin:定义可复用的代码片段,不含构造函数
  • with:在类中使用混入,可组合多个
  • on:限制混入只能用于特定类型的子类

代码示例

dart 复制代码
void main() {
  var bird = Bird();
  bird.fly();   // Flying
  bird.swim();  // Swimming

  var fish = Fish();
  fish.swim();  // Swimming
  // fish.fly(); // 错误:Fish 没有 fly
}

// 定义混入
mixin Flyable {
  void fly() => print('Flying');
}

mixin Swimmable {
  void swim() => print('Swimming');
}

// 使用 with 组合混入
class Bird with Flyable, Swimmable {}

class Fish with Swimmable {}

// 限制混入作用域
mixin Walker on Animal {
  void walk() => print('Walking');
}

class Animal {}

class Dog extends Animal with Walker {}  // 合法,Walker 要求 on Animal
// class Table with Walker {}  // 错误:Table 不是 Animal 的子类

解析

  • 混入可以替代多重继承,解决代码复用问题。
  • 如果一个混入使用了 on,则只能被 on 指定类型的子类使用。
  • 混入不能有构造函数。

2.8 枚举

知识点

  • 基本枚举enum 关键字,列出常量值
  • 扩展枚举:Dart 2.17+ 支持字段、方法、构造函数
  • 访问方式EnumName.value,可获取 indexname

代码示例

dart 复制代码
void main() {
  // 基本枚举
  var color = Color.red;
  print(color.index);   // 0
  print(color.name);    // 'red'

  switch (color) {
    case Color.red:
      print('红色');
      break;
    case Color.green:
      print('绿色');
      break;
    case Color.blue:
      print('蓝色');
      break;
  }

  // 扩展枚举
  print(Status.success.message);
  print(Status.pending.displayName);

  // 遍历枚举值
  for (var status in Status.values) {
    print(status);
  }
}

// 基本枚举
enum Color { red, green, blue }

// 增强枚举(Dart 2.17+)
enum Status {
  pending('等待中', 0),
  success('成功', 1),
  error('失败', -1);

  final String displayName;
  final int code;

  const Status(this.displayName, this.code);

  String get message => displayName;
}

解析

  • 枚举可用于表示一组固定的常量。
  • 增强枚举可以拥有实例变量、构造函数(必须是 const)和方法。
  • Enum.values 可以获取所有枚举值的列表。

总结

第二章全面覆盖了 Dart 面向对象编程的核心概念,包括类、构造函数、私有成员、继承、抽象类/接口、混入以及枚举。这些知识是构建 Flutter 应用的基石,熟练掌握后可以编写出结构清晰、可复用的代码。下一章将进入 函数式编程与高阶特性

相关推荐
迷枫7121 小时前
DCA 考试重点初版
学习
●VON1 小时前
AtomGit Flutter鸿蒙客户端:API客户端与网络层
flutter·华为·架构·跨平台·harmonyos·鸿蒙
留白_1 小时前
numpy学习
学习·numpy
花岛溯1 小时前
AI产品经理学习 DAY4 · Cursor 生成figma 原型
学习·产品经理·figma
-To be number.wan1 小时前
计算机组成原理 | Cache替换算法
学习·计算机组成原理
kgduu2 小时前
cosmos学习笔记
笔记·学习
核电机组2 小时前
IOS原生APP集成Flutter
flutter·ios
唔662 小时前
在 Flutter 混合开发中,Android 原生层通知 Dart 界面更新状态
android·flutter
AI_零食2 小时前
鸿蒙PC Electron跨平台应用开发:辗转相除法计算器实现详解
前端·学习·华为·electron·开源·鸿蒙·鸿蒙系统