值对象是否可以有行为(即方法)?如果可以,这些行为应遵循哪些设计原则以保持良好的设计模式?
值对象不仅可以有行为(即方法),而且合理的行为能够增强其表达力和实用性。值对象的关键特性在于其不可变性和对等性(两个具有相同值的值对象被认为是等价的)。基于这些特点,为值对象添加行为时,应当遵循一系列设计原则,以确保设计的合理性与优雅。
-
行为不改变状态:值对象的一个核心原则就是不可变性,这意味着任何对其的操作都不能改变它的内部状态。因此,为值对象添加的方法不应修改其状态,而是通过返回一个新的值对象来实现相同的功能,比如
Money类中的add方法,它不会修改调用它的Money实例,而是返回一个新的Money对象,表示两笔金额的总和。 -
行为应保持等价性:值对象的行为应当确保如果对两个等价的值对象执行相同的操作,结果也应该是等价的。例如,两个金额相等的
Money对象,无论他们之前带有不同的ID(假设这样的设计),当调用add方法时,它们的行为和结果应该一致。 -
纯粹的功能性:值对象的行为应该是纯粹的功能性的,意味着方法的结果仅依赖于输入参数,不依赖于外部状态或环境信息。这样的设计使得值对象的行为更容易预测,也有利于测试。
-
增强表达力:值对象的方法应当增强其表达力,使代码更加清晰明了,减少歧义。比如,可以通过定义
Money.add、Money.subtract等操作,而非直接访问内部值进行加减运算,这样能更好地传达代码的意图。 -
避免副作用:设计值对象的行为时,应尽量避免任何副作用。副作用不仅可能导致不可预测的行为,还会影响值对象的不可变性和等价性。
示例:
public class Money {
private final BigDecimal amount;
public Money(BigDecimal amount) {
this.amount = amount;
}
public Money add(Money other) {
return new Money(this.amount.add(other.amount));
}
public Money subtract(Money other) {
return new Money(this.amount.subtract(other.amount));
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Money money = (Money) o;
return amount.equals(money.amount);
}
// hashCode等其他方法
}
在上述示例中,Money类是一个典型的值对象,提供了add和subtract方法用于金额运算,这两个方法都不改变对象状态,而是返回了新的Money实例,同时重写了equals方法以支持等价性比较。