Menu
CoddyTech

公有成员与私有成员

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

封装是面向对象编程的核心原则之一。它指的是控制对类内部数据的访问,决定哪些内容可以对外公开,哪些内容应该保持隐藏。

在 Dart 中,类成员(字段和方法)默认是公开的。这意味着任何代码都可以直接访问它们:

class BankAccount {
  String owner;
  double balance;
  
  BankAccount(this.owner, this.balance);
}

var account = BankAccount('Alice', 1000);
account.balance = -500;  // 任何人都能直接修改它!

这会带来问题。没有任何机制能阻止设置无效的余额。

为了保护内部数据,Dart 使用私有成员。成员名称以下划线 _ 开头时,就会变为私有成员:

class BankAccount {
  String owner;
  double _balance;  // 私有:以下划线开头
  
  BankAccount(this.owner, this._balance);
  
  double get balance => _balance;  // 受控访问
}

现在,外部无法直接访问定义该类的库中的 _balance。外部代码必须改用公共 getter。这样你就能控制数据的读取和修改方式,确保对象始终处于有效状态。

challenge icon

挑战

简单

我们来构建一个简单的密码管理器,演示公有成员和私有成员之间的区别。你将看到,下划线前缀如何保护敏感数据,防止从类的库外部直接访问。

你将创建两个文件来整理代码:

  • credential.dart:定义一个用于存储网站登录信息的 Credential 类。这个类应包含:
    • 一个公有的 String website,任何人都可以看到它对应的网站
    • 一个公有的 String username,用户名可以公开显示
    • 一个私有的 String _password,实际密码必须受到保护
    • 一个接收这三个值的构造函数
    • 一个公有的 getter password,用于返回私有的 _password(受控访问)
    • 一个 getMaskedPassword() 方法,将密码中的所有字符替换为星号 *(长度与实际密码相同)
    • 一个 displayCredential() 方法,安全地输出凭据的信息(显示掩码后的密码,而不是真实密码)
  • main.dart:导入凭据类,并演示封装如何保护密码:
    • 为网站 'github.com'、用户名 'dev_user' 和密码 'secret123' 创建一个凭据
    • 为网站 'email.com'、用户名 'john_doe' 和密码 'myP@ss' 创建另一个凭据
    • 对于每个凭据,调用 displayCredential(),然后使用公有 getter 访问密码长度,并输出 Actual password length: [length]

displayCredential() 方法应按以下格式输出:

--- Credential ---
Website: [website]
Username: [username]
Password: [maskedPassword]

预期输出:

--- Credential ---
Website: github.com
Username: dev_user
Password: *********
Actual password length: 9
--- Credential ---
Website: email.com
Username: john_doe
Password: ******
Actual password length: 6

亲手试试

import 'credential.dart';

void main() {
  // TODO: 为 github.com 创建一个凭据
  // 网站:'github.com',用户名:'dev_user',密码:'secret123'
  
  // TODO: 对第一个凭据调用 displayCredential()
  
  // TODO: 使用公共 getter 输出实际密码长度
  // 格式:"Actual password length: [length]"
  
  // TODO: 为 email.com 创建一个凭据
  // 网站:'email.com',用户名:'john_doe',密码:'myP@ss'
  
  // TODO: 对第二个凭据调用 displayCredential()
  
  // TODO: 使用公共 getter 输出实际密码长度
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: Dart 在线编译器