Java 中的值对象模式:使用不可变数据类型提高性能
大约 3 分钟
也称为
- 嵌入值
- 不可变对象
- 内联值
- 集成值
值对象设计模式的意图
Java 中的值对象模式创建不可变对象,这些对象代表领域中没有概念身份的描述性方面。它旨在通过将频繁访问的不可变数据直接存储在使用它的对象中(而不是单独存储)来提高性能并减少内存开销。
值对象模式的详细解释,并附带实际案例
现实世界中的例子
考虑名片的情况。在本例中,
BusinessCard
类被实现为一个值对象,以演示 Java 应用程序中不可变数据处理和效率。在现实世界中,名片包含诸如姓名、职位、电话号码和电子邮件地址等信息。此信息代表描述个人联系方式的一组特定且完整的属性,但本身没有身份,除了这些信息之外。在软件系统中,您可以创建一个
BusinessCard
类作为值对象。此类将是不可变的,这意味着一旦使用个人详细信息创建了一个BusinessCard
对象,这些详细信息就不能更改。如果您需要不同的名片,则创建新的实例而不是修改现有实例。两个BusinessCard
对象的相等性将基于它们包含的数据而不是它们的内存地址,确保具有相同详细信息的两个名片被视为相等。这反映了现实生活中名片的使用方式以及根据其内容而不是物理卡本身进行比较的方式。
通俗地说
当值对象的属性具有相同的值时,它们是相等的。
维基百科说
在计算机科学中,值对象是一个小型对象,它表示一个简单的实体,其相等性不基于身份:即,当两个值对象具有相同的值时,它们是相等的,而不一定是同一个对象。
Java 中值对象模式的编程示例
角色扮演游戏中存在一个用于英雄属性的类。属性包含诸如力量、智力和运气等属性。当所有属性相等时,不同英雄的属性应该相等。
以下是作为值对象的 HeroStat
类。请注意使用 Lombok 的 @Value
注解。
@Value(staticConstructor = "valueOf")
@ToString
class HeroStat {
int strength;
int intelligence;
int luck;
}
该示例创建了三个不同的 HeroStat
并比较了它们的相等性。
public static void main(String[] args) {
var statA = HeroStat.valueOf(10, 5, 0);
var statB = HeroStat.valueOf(10, 5, 0);
var statC = HeroStat.valueOf(5, 1, 8);
LOGGER.info("statA: {}", statA);
LOGGER.info("statB: {}", statB);
LOGGER.info("statC: {}", statC);
LOGGER.info("Are statA and statB equal? {}", statA.equals(statB));
LOGGER.info("Are statA and statC equal? {}", statA.equals(statC));
}
以下是控制台输出。
20:11:12.199 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0)
20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0)
20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=5, intelligence=1, luck=8)
20:11:12.202 [main] INFO com.iluwatar.value.object.App - Is statA and statB equal : true
20:11:12.203 [main] INFO com.iluwatar.value.object.App - Is statA and statC equal : false
何时在 Java 中使用值对象模式
使用值对象时
- 当您需要具有减少内存开销的高性能 Java 应用程序时,尤其是需要高效数据管理的系统,请应用值对象模式。
- 当表示一组属性时,这些属性共同描述一个实体,但没有身份。
- 当对象的相等性基于属性的值,而不是身份时。
- 当您需要确保在创建后无法更改对象时。
- 应用程序需要高性能,并且涉及的数据是不可变的。
- 减少内存占用至关重要,尤其是在资源有限的环境中。
- 对象经常访问特定的一段不可变数据。
值对象模式 Java 教程
值对象模式在 Java 中的实际应用
- 实现复杂数据类型,例如货币值、度量值和其他特定于域的值。
- java.util.Optional
- java.time.LocalDate
- java.awt.Color
- joda-time、money、beans
值对象模式的优缺点
优点
- 通过使对象不可变来简化代码。
- 线程安全,因为对象的状态在创建后无法更改。
- 更容易理解和维护。
- 通过避免为不可变数据进行单独的分配来减少内存开销。
- 通过最大限度地减少内存访问并减少缓存未命中来提高性能。
权衡取舍
- 对于复杂对象,每次更改都要创建一个新对象效率可能较低。
- 由于创建表示不同状态的多个对象而导致的内存使用增加。
- 增加了对象设计的复杂性,并且可能导致紧密耦合的系统。
- 修改嵌入值需要更改嵌入此值的每个对象,这可能会使维护复杂化。
相关的 Java 设计模式
- 工厂方法:通常用于创建值对象的实例。
- 享元:共享对象以使用最少的内存支持大量对象,在意图上有些类似,但在实现上有所不同。
- 建造者:可以一步一步地构造复杂的值对象。
- 原型:可以用于克隆现有的值对象,尽管克隆在不可变对象中不太常见。
- 单例:确保一个类只有一个实例,并提供一个全局访问点,可以用来管理共享嵌入值。