在我看来,这种变化与得墨忒耳法则没有任何关系。本质上,该法则是关于通过让方法调用整个其他对象链来将对象图的结构编码到代码中。例如,假设在汽车保险应用程序中,客户有保单,保单有车辆,车辆分配有司机,司机有出生日期,因此有年龄。你可以想象下面的代码:
public boolean hasUnderageDrivers(Customer customer) {
for (Vehicle vehicle : customer.getPolicy().getVehicles()) {
for (Driver driver : vehicle.getDrivers()) {
if (driver.getAge() < 18) {
return true;
}
}
}
return false;
}
这将违反得墨忒耳法则,因为该代码现在拥有不需要知道的内部知识。它知道司机被分配到车辆,而不是仅仅被分配到整个保险单。如果将来保险公司决定司机只是在保单上,而不是被分配到特定的车辆,那么这个代码就必须改变。
问题是它调用其参数的方法,getPolicy()
然后是另一个,,getVehicles()
然后是另一个,,getDrivers()
然后是另一个,getAge()
。得墨忒耳法则说,一个类的方法应该只调用方法:
(最后一个可能是单元测试的问题,您可能希望由工厂注入或创建对象,而不是直接在本地创建,但这与得墨忒耳定律无关。)
为了解决这个问题,hasUnderageDrivers()
我们可以传入Policy
对象,我们可以有一个方法Policy
知道如何确定策略是否有未成年司机:
public boolean hasUnderageDrivers(Policy policy) {
return policy.hasUnderageDrivers();
}
向下调用一个级别,customer.getPolicy().hasUnderageDrivers()
可能是可以的——得墨忒耳法则是一个经验法则,而不是一成不变的规则。您也可能不必担心不太可能改变的事情;Driver
大概总是会继续有一个出生日期和一个getAge()
方法。
但是回到你的例子,如果我们用公共字段替换所有这些 getter 会发生什么?它对得墨忒耳法则毫无帮助。您仍然可以遇到与第一个示例完全相同的问题。考虑:
public boolean hasUnderageDrivers(Customer customer) {
for (Vehicle vehicle : customer.policy.vehicles) {
for (Driver driver : vehicle.drivers) {
if (driver.age < 18) {
return true;
}
}
}
return false;
}
(我什至已经转换driver.getAge()
为driver.age
,尽管这可能是基于出生日期而不是简单字段的计算。)
请注意,当我们使用公共字段而不是 getter 编写代码时,会出现与如何将对象图组合在一起的嵌入知识(客户的政策具有具有车辆的车辆)的完全相同的问题。问题与这些部分是如何组合在一起的,而不是与 getter 是否被调用有关。
顺便说一句,更喜欢 getter 而不是(final?)公共字段的正常原因是您稍后可能需要在它们后面添加一些逻辑。年龄被替换为基于出生日期和今天日期的计算,或者 setter 需要进行一些验证(null
例如,如果您通过,则抛出)与之相关联。我以前从未听说过在这种情况下援引得墨忒耳法则。