Menu
CoddyTech

深入了解 Getter 和 Setter

本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 33 课,共 110 课。

将 getter 和 setter 与私有字段结合使用,可以成为封装的强大工具。它们让你在提供简洁的公共接口的同时,完全掌控数据的访问和修改方式。

一种常见模式是将私有字段与公共 getter 和包含验证逻辑的 setter 配对:

class Temperature {
  double _celsius = 0;
  
  double get celsius => _celsius;
  
  set celsius(double value) {
    if (value < -273.15) {
      _celsius = -273.15;  // 最低为绝对零度
    } else {
      _celsius = value;
    }
  }
}

Setter 可以执行业务规则,确保对象始终处于有效状态。

你还可以创建计算属性获取器,从私有数据中推导出值:

class Rectangle {
  double _width;
  double _height;
  
  Rectangle(this._width, this._height);
  
  double get area => _width * _height;      // 计算得出
  double get perimeter => 2 * (_width + _height);
  
  double get width => _width;
  set width(double value) {
    if (value > 0) _width = value;
  }
}

有时你只想提供只读访问权限。只需提供 getter,不提供 setter:

class Order {
  final DateTime _createdAt = DateTime.now();
  
  DateTime get createdAt => _createdAt;  // 只读
}

这种模式让外部代码可以查看数据,同时防止任何修改,私有字段与仅有的 getter 结合,实现了真正的只读访问。

challenge icon

挑战

简单

让我们构建一个商品库存系统,展示 getter 和 setter 如何控制数据访问。你将创建一个类,在保护内部数据的同时提供计算属性和验证功能。

你需要将代码分成两个文件:

  • product.dart:定义一个 Product 类,通过适当的封装来管理库存。你的商品类应包含:
    • 一个公有的 String name
    • 一个私有的 double _price
    • 一个私有的 int _quantity
    • 一个接收这三个值的构造函数
    • 一个返回私有价格的 getter price
    • 一个只接受大于 0 的值的 setter price(忽略无效值)
    • 一个返回私有数量的 getter quantity
    • 一个只接受大于或等于 0 的值的 setter quantity(忽略负值)
    • 一个返回 _price * _quantity 的计算 getter totalValue
    • 一个计算 getter isInStock,当数量大于 0 时返回 true
    • 一个只读 getter sku,通过返回名称的前 3 个字符的大写形式,再接上数量来生成简单的 SKU(例如,数量为 25 的 "Laptop" 对应 LAP25)
    • 一个用于显示商品详情的方法 displayProduct()
  • main.dart:导入商品类,并演示 getter 和 setter 如何控制访问:
    • 创建一个名为 'Laptop'、价格为 999.99、数量为 25 的商品
    • 调用 displayProduct()
    • 打印 In stock: [isInStock]
    • 打印 SKU: [sku]
    • 尝试将价格设为 -50.0(应被忽略)
    • 将价格设为 899.99(有效更改)
    • 尝试将数量设为 -10(应被忽略)
    • 将数量设为 0(有效更改)
    • 调用 displayProduct()
    • 打印 In stock: [isInStock]
    • 打印 SKU: [sku]

displayProduct() 方法应按以下格式打印:

--- Product Info ---
Name: [name]
Price: $[price]
Quantity: [quantity]
Total Value: $[totalValue]

预期输出:

--- Product Info ---
Name: Laptop
Price: $999.99
Quantity: 25
Total Value: $24999.75
In stock: true
SKU: LAP25
--- Product Info ---
Name: Laptop
Price: $899.99
Quantity: 0
Total Value: $0.0
In stock: false
SKU: LAP0

亲手试试

import 'product.dart';

void main() {
  // TODO: 创建一个名为 'Laptop'、价格为 999.99、数量为 25 的商品

  // TODO: 调用 displayProduct()

  // TODO: 打印 "In stock: [isInStock]"

  // TODO: 打印 "SKU: [sku]"

  // TODO: 尝试将价格设为 -50.0(应被忽略)

  // TODO: 将价格设为 899.99(有效修改)

  // TODO: 尝试将数量设为 -10(应被忽略)

  // TODO: 将数量设为 0(有效修改)

  // TODO: 调用 displayProduct()

  // TODO: 打印 "In stock: [isInStock]"

  // TODO: 打印 "SKU: [sku]"
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Dart 在线编译器