信息隐藏
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 34 课,共 110 课。
信息隐藏是封装背后的原则,也就是说,类应该隐藏其内部工作原理,只公开必要的内容。你已经学习了相关机制(私有字段、获取器、设置器),但真正的目标是设计出易于使用且不易被误用的类。
考虑一个用于管理用户密码的类。内部存储和哈希逻辑应完全隐藏:
class UserAccount {
String _username;
String _passwordHash;
UserAccount(this._username, String password)
: _passwordHash = _hashPassword(password);
static String _hashPassword(String password) {
return 'hashed_$password'; // 简化示例
}
bool verifyPassword(String password) {
return _passwordHash == _hashPassword(password);
}
String get username => _username;
}外部代码看不到密码哈希,也不知道它是如何存储的。它们只需调用 verifyPassword()。这种分离意味着你可以彻底更改哈希算法,而不会影响任何使用这个类的代码。
关键在于从外部向内思考你的类。
问问自己:“使用这个类的人实际需要什么?”只公开这些内容,其他内容都设为私有。这样就能明确区分类的功能(它的公共接口)和实现方式(它的私有实现)。
挑战
简单让我们构建一个安全的钱包系统,展示信息隐藏的实际应用。你将创建一个数字钱包,用于管理用户的余额和交易历史,并将所有敏感的内部细节完全隐藏起来,不让外部代码访问。
你将把代码分成两个文件:
wallet.dart:创建一个Wallet类,安全地管理资金。钱包应公开存储所有者的姓名,但其他所有内容都应通过简洁的公共接口隐藏起来:- 内部余额和交易记录应设为私有,外部代码不应看到你如何存储或跟踪资金
- 使用一个私有方法在内部记录交易(存储类似
"Deposit: $50.0"或"Withdrawal: $30.0"这样的条目) - 提供一个公共的
deposit(double amount)方法,用于存入资金(仅当金额为正数时),并在内部记录交易 - 提供一个公共的
withdraw(double amount)方法,仅当资金充足且金额为正数时才取出资金,并在内部记录交易。成功时返回true,否则返回false - 提供一个公共 getter
balance,用于返回当前余额(只读访问) - 提供一个公共方法
getTransactionCount(),用于返回已记录的交易数量(不公开实际的交易列表) - 提供一个公共方法
getLastTransaction(),用于返回最近一笔交易的字符串;如果没有交易,则返回"No transactions" - 添加一个
printSummary()方法,用于显示钱包状态
main.dart:导入钱包,并演示信息隐藏如何创建简洁、安全的接口:- 为所有者
"Sarah"创建一个钱包 - 存入
100.0 - 存入
50.0 - 尝试取出
200.0,并根据结果打印"Withdrawal of 200.0: [success/failed]" - 取出
30.0,并打印"Withdrawal of 30.0: [success/failed]" - 调用
printSummary() - 打印
"Transaction count: [count]" - 打印
"Last transaction: [transaction]"
- 为所有者
printSummary() 方法应打印:
=== Wallet Summary ===
Owner: [ownerName]
Balance: $[balance]注意,外部代码可以通过清晰、明确的方法与钱包交互,而完全不必了解余额是如何存储的,或交易是如何在内部跟踪的。实现细节会被完全隐藏起来。你可以更改交易的存储方式,而不会影响任何使用该钱包的代码。
预期输出:
Withdrawal of 200.0: failed
Withdrawal of 30.0: success
=== Wallet Summary ===
Owner: Sarah
Balance: $120.0
Transaction count: 3
Last transaction: Withdrawal: $30.0亲手试试
import 'wallet.dart';
void main() {
// TODO:为所有者 "Sarah" 创建一个钱包
// TODO:存入 100.0
// TODO:存入 50.0
// TODO:尝试取出 200.0,并打印结果
// 格式:"Withdrawal of 200.0: [success/failed]"
// TODO:取出 30.0,并打印结果
// 格式:"Withdrawal of 30.0: [success/failed]"
// TODO:调用 printSummary()
// TODO:打印交易笔数
// 格式:"Transaction count: [count]"
// TODO:打印最后一笔交易
// 格式:"Last transaction: [transaction]"
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器