Menu
CoddyTech

数据隐藏的实现

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

数据隐藏不仅仅是使用 private 字段。它还意味着设计类时,让内部实现细节对外部代码完全不可见,只通过简洁的公共接口公开必要的内容。

想想一个用于跟踪用户密码的类。你不希望任何人访问原始密码,甚至不希望他们读取它:

public class UserAccount
{
    private string passwordHash;
    
    public void SetPassword(string password)
    {
        passwordHash = HashPassword(password);
    }
    
    public bool VerifyPassword(string password)
    {
        return HashPassword(password) == passwordHash;
    }
    
    private string HashPassword(string password)
    {
        return password.GetHashCode().ToString();
    }
}

注意,你无法取回密码,甚至无法取回哈希值。外部代码只能设置密码或验证密码,内部存储机制完全隐藏。HashPassword 方法也是私有的,因为它属于实现细节,即使发生变化,也不会影响类的使用方式。

这种做法可以保护你的类不被误用,也让你以后能自由更改内部实现。如果你决定使用不同的哈希算法,也不会导致外部代码出错,因为没有任何代码依赖密码的存储方式。

challenge icon

挑战

简单

让我们构建一个安全的钱包系统,来展示真正的数据隐藏。你将创建一个数字钱包,其中的余额受到完全保护,无法直接访问。外部代码只能存款、取款,以及检查交易是否可行,但绝不能直接查看或操作实际余额。

你将把代码分到两个文件中:

  • Wallet.cs:在 Finance 命名空间中创建一个 Wallet 类,让余额完全隐藏。钱包应包含:
    • 一个用于存储余额的私有字段(decimal)
    • 一个私有方法 FormatBalance(),用于将余额格式化为货币字符串,例如 "$123.45"。这是一个不应公开的内部辅助方法
    • 一个公共方法 Deposit(decimal amount),仅当金额为正数时才增加余额。成功时返回 true,否则返回 false
    • 一个公共方法 Withdraw(decimal amount),仅当金额为正数且不超过当前余额时才扣减余额。成功时返回 true,否则返回 false
    • 一个公共方法 CanAfford(decimal amount),如果余额大于或等于金额,则返回 true,否则返回 false
    • 一个公共方法 GetStatement(),在内部使用私有方法 FormatBalance(),并返回 "Current balance: {formatted balance}"
    请注意,无法直接读取或设置余额,你只能通过受控方法与它交互!
  • Program.cs:在主文件中创建一个 Wallet,并使用输入值执行一系列交易。展示钱包如何保护其内部状态,同时通过公共接口提供实用功能。

你将收到三个输入:

  • 初始存款金额(decimal)
  • 尝试取款的金额(decimal)
  • 要检查是否有足够余额支付的金额(decimal)

按以下格式打印输出:

Deposit {amount}: {True/False}
{GetStatement() result}
Withdraw {amount}: {True/False}
{GetStatement() result}
Can afford {amount}: {True/False}

例如,如果输入为 100.50、30.25 和 80.00,输出应为:

Deposit 100.50: True
Current balance: $100.50
Withdraw 30.25: True
Current balance: $70.25
Can afford 80.00: False

这里的关键在于,外部代码不会直接接触余额字段。即使是格式化后的余额字符串,也要通过一个在内部使用私有辅助方法的公共方法获取。这就是数据隐藏:实现细节完全不可见,你可以自由更改余额的存储或格式化方式,而不会破坏使用钱包的代码!

亲手试试

using System;
using Finance;

class Program
{
    public static void Main(string[] args)
    {
        // 读取输入值
        decimal depositAmount = Convert.ToDecimal(Console.ReadLine());
        decimal withdrawAmount = Convert.ToDecimal(Console.ReadLine());
        decimal checkAmount = Convert.ToDecimal(Console.ReadLine());

        // TODO:创建一个 Wallet 实例
        
        // TODO:执行存款操作,并按以下格式打印结果:"Deposit {amount}: {True/False}"
        
        // TODO:使用 GetStatement() 打印对账单
        
        // TODO:执行取款操作,并按以下格式打印结果:"Withdraw {amount}: {True/False}"
        
        // TODO:使用 GetStatement() 打印对账单
        
        // TODO:检查余额是否足够,并按以下格式打印结果:"Can afford {amount}: {True/False}"
    }
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: C# 在线编译器