Java 中的私有类数据模式:通过封装保护数据完整性
大约 3 分钟
又称
- 数据隐藏
- 封装
私有类数据设计模式的意图
Java 中的私有类数据设计模式专注于限制对对象内部状态的访问,通过受控方法访问增强安全性并降低数据损坏风险。
私有类数据模式的详细解释及现实世界示例
现实世界示例
私有类数据模式的现实世界类比是银行保护客户账户信息的方式。就像一个包含私有字段的类一样,银行会将敏感数据(如账户余额、交易历史和个人信息)保密,并且只能通过特定方法访问。客户通过定义明确的接口(如自动柜员机或网上银行门户网站)与他们的账户进行交互,这些接口强制执行安全性和验证规则,确保防止未经授权的访问或修改。这种受控访问机制确保了数据的完整性和安全性,类似于私有类数据在软件设计中保护和管理对类属性的访问的方式。
通俗地说
私有类数据模式通过将数据与使用它的方法分离到一个维护数据状态的类中,防止对旨在不可变的数据的操控。
维基百科说
私有类数据是计算机编程中的一种设计模式,用于封装类属性及其操作。
Java 中私有类数据模式的编程示例
假设你正在为家里的晚餐做炖肉。你想要阻止你的家人在你还在准备炖肉的时候尝它。如果他们尝了,可能就没有足够的炖肉留到晚餐了。
首先,我们有一个 `Stew` 类,它的数据不受私有类数据的保护,这使得炖肉的配料可以被类方法修改。
@Slf4j
public class Stew {
private int numPotatoes;
private int numCarrots;
private int numMeat;
private int numPeppers;
public Stew(int numPotatoes, int numCarrots, int numMeat, int numPeppers) {
this.numPotatoes = numPotatoes;
this.numCarrots = numCarrots;
this.numMeat = numMeat;
this.numPeppers = numPeppers;
}
public void mix() {
LOGGER.info("Mixing the stew we find: {} potatoes, {} carrots, {} meat and {} peppers",
numPotatoes, numCarrots, numMeat, numPeppers);
}
public void taste() {
LOGGER.info("Tasting the stew");
if (numPotatoes > 0) {
numPotatoes--;
}
if (numCarrots > 0) {
numCarrots--;
}
if (numMeat > 0) {
numMeat--;
}
if (numPeppers > 0) {
numPeppers--;
}
}
}
现在,我们有 `ImmutableStew` 类,它的数据受 `StewData` 记录的保护。`ImmutableStew` 中的方法无法操作 `StewData` 类的数据。
public record StewData(int numPotatoes, int numCarrots, int numMeat, int numPeppers) {}
@Slf4j
public class ImmutableStew {
private final StewData data;
public ImmutableStew(int numPotatoes, int numCarrots, int numMeat, int numPeppers) {
data = new StewData(numPotatoes, numCarrots, numMeat, numPeppers);
}
public void mix() {
LOGGER
.info("Mixing the immutable stew we find: {} potatoes, {} carrots, {} meat and {} peppers",
data.getNumPotatoes(), data.getNumCarrots(), data.getNumMeat(), data.getNumPeppers());
}
}
让我们尝试创建每个类的实例并调用它们的方法
public static void main(String[] args) {
// stew is mutable
var stew = new Stew(1, 2, 3, 4);
stew.mix();
stew.taste();
stew.mix();
// immutable stew protected with Private Class Data pattern
var immutableStew = new ImmutableStew(2, 4, 3, 6);
immutableStew.mix();
}
程序输出
08:00:08.210 [main] INFO com.iluwatar.privateclassdata.Stew -- Mixing the stew we find: 1 potatoes, 2 carrots, 3 meat and 4 peppers
08:00:08.212 [main] INFO com.iluwatar.privateclassdata.Stew -- Tasting the stew
08:00:08.212 [main] INFO com.iluwatar.privateclassdata.Stew -- Mixing the stew we find: 0 potatoes, 1 carrots, 2 meat and 3 peppers
08:00:08.213 [main] INFO com.iluwatar.privateclassdata.ImmutableStew -- Mixing the immutable stew we find: 2 potatoes, 4 carrots, 3 meat and 6 peppers
何时在 Java 中使用私有类数据模式
在以下情况下使用私有类数据模式
- 当你想要保护对象状态的完整性时。
- 当你需要限制对对象内部数据的可见性以防止意外修改时。
- 在多个类需要共享访问一些公共数据而无需直接暴露它的时候。
Java 中私有类数据模式的现实世界应用
- Java Bean,其中属性通过 getter 和 setter 访问。
- 在许多 Java 库中,其中内部状态对用户隐藏以确保一致性和安全性。
- 企业应用程序,其中敏感数据需要受到保护,防止直接访问。
私有类数据模式的优缺点
优点
- 增强安全性:通过封装数据,降低了意外数据损坏的风险。
- 易于维护:对数据内部表示的更改不会影响外部代码。
- 改进抽象:用户与简化的接口进行交互,而无需担心数据管理的复杂性。
权衡
- 性能开销:额外的函数调用(getter/setter)可能会引入轻微的性能开销。
- 复杂性:由于为数据访问添加了额外的函数层,可能会增加类设计的复杂性。
相关的 Java 设计模式
- 代理:两种模式都限制对底层对象的访问,但代理控制对对象本身的访问,而私有类数据控制对数据的访问。
- 单例:确保一个类只有一个实例,并提供对它的全局访问点;通常用于管理具有受控访问权限的共享数据。
- 装饰器:在不改变其结构的情况下为对象添加行为;可以与私有类数据结合使用以私有地管理附加状态。