信息隐藏
本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 41 课,共 91 课。
信息隐藏是封装背后的原则,也就是类应该只公开必要的内容,并隐藏其内部实现细节。访问修饰符和 getter/setter 是实现这一原则的工具,而信息隐藏则是指导你如何使用这些工具的设计理念。
目标是明确区分类做什么(它的公共接口)和它如何实现(它的内部实现)。这样分离后,你可以更改内部实现,而不影响使用该类的代码:
<?php
class Temperature {
private float $celsius;
public function setCelsius(float $value): void {
$this->celsius = $value;
}
public function getCelsius(): float {
return $this->celsius;
}
public function getFahrenheit(): float {
return ($this->celsius * 9/5) + 32;
}
}
$temp = new Temperature();
$temp->setCelsius(25);
echo $temp->getCelsius() . "C = " . $temp->getFahrenheit() . "F";
输出:
25C = 77F这个类在内部以摄氏度存储温度,但用户不需要知道这一点。以后你可以将内部存储改为华氏度或开尔文,只要公共方法的使用方式保持不变,外部代码就不会出问题。
关键点:信息隐藏可以保护你的代码免受变化的影响。隐藏实现细节,只公开稳定的接口,这样你的类就会更易于维护和修改。
挑战
简单让我们构建一个货币转换器,演示信息隐藏的实际应用。你将创建一个类,在内部以一种货币存储金额,同时能够轻松地转换多种货币,外部代码完全不需要知道数据实际上是如何存储的。
你将把代码分成两个文件:
Money.php:创建一个Money类,在内部将所有金额存储为分(整数),以避免浮点精度问题。这个实现细节应对类的使用者完全隐藏。这个类应提供:- 一个用于存储分金额的私有属性
setDollars(float $amount):接受美元金额,并在内部将其存储为分getDollars():以美元形式返回金额(浮点数,保留 2 位小数)setEuros(float $amount):接受欧元,并按汇率 1 EUR = 1.10 USD 转换为分getEuros():返回转换为欧元后的金额(浮点数,保留 2 位小数)getInternalValue():返回原始的分值(整数),用于调试
main.php:引入 Money 文件。你会收到两个输入:美元金额和欧元金额。创建一个Money实例。首先,设置美元金额(转换为浮点数),并打印三行:美元金额、对应的欧元金额,以及内部的分值。然后,设置欧元金额(转换为浮点数),并再次打印相同的三个值。
这种设计的优点是,外部代码使用熟悉的美元和欧元金额,却完全不知道所有金额在内部都以分存储。之后你可以改用其他基础货币或不同的精度策略来进行内部存储,只要公共方法仍能正常工作,外部代码就不需要做任何更改。
美元和欧元金额都必须格式化为恰好保留 2 位小数。每个值都应单独占一行,总共输出六行。
亲手试试
<?php
require_once 'Money.php';
// 读取输入
$dollarAmount = floatval(trim(fgets(STDIN)));
$euroAmount = floatval(trim(fgets(STDIN)));
// TODO:创建一个 Money 实例
// TODO:设置美元金额并打印:
// 美元值(保留 2 位小数)
// 等值欧元金额(保留 2 位小数)
// 内部的美分值(整数)
// TODO:设置欧元金额并打印:
// 美元值(保留 2 位小数)
// 等值欧元金额(保留 2 位小数)
// 内部的美分值(整数)
?>这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: PHP 在线编译器