在面向对象的设计范式中,不应在对象本身之外修改对象。对对象状态的任何更改都应通过对象上的方法来完成。
因此,void predictPrice(Item item)
作为其他类的成员函数是错误的。在C时代可能是可以接受的,但是对于Java和C ++,对对象的修改意味着与对象的更深层次的耦合,这很可能会导致其他设计问题(当您重构类并更改其字段时,现在需要将“ predictPrice”更改为其他文件。
返回一个新对象,没有相关的副作用,传入的参数不会更改。您(predictPrice方法)不知道在哪里使用该参数。是Item
一个哈希某处的钥匙吗?您这样做是否更改了其哈希码?是否有人坚持要求它不会改变?
这些设计问题强烈建议您不要修改对象(在许多情况下,我会主张不变性),如果这样做,状态的更改应由对象本身而不是某些东西控制和包含。其他在课堂之外。
让我们看一下如果弄乱了哈希中某些字段的情况会发生什么。让我们看一些代码:
import java.util.*;
public class Main {
public static void main (String[] args) {
Set set = new HashSet();
Data d = new Data(1,"foo");
set.add(d);
set.add(new Data(2,"bar"));
System.out.println(set.contains(d));
d.field1 = 2;
System.out.println(set.contains(d));
}
public static class Data {
int field1;
String field2;
Data(int f1, String f2) {
field1 = f1;
field2 = f2;
}
public int hashCode() {
return field2.hashCode() + field1;
}
public boolean equals(Object o) {
if(!(o instanceof Data)) return false;
Data od = (Data)o;
return od.field1 == this.field1 && od.field2.equals(this.field2);
}
}
}
乙二酮
而且我承认这不是最好的代码(直接访问字段),但是它的目的是证明可变数据被用作HashMap的键,或者在这种情况下,将其放入HashSet。
此代码的输出是:
true
false
发生的事情是,插入哈希码时使用的是哈希对象中的位置。更改用于计算hashCode的值不会重新计算哈希本身。这有将任何可变对象作为哈希键的危险。
因此,回到问题的原始方面,被调用的方法并不“知道”作为参数使用的对象。提供“让对象变异对象”作为执行此操作的唯一方法意味着存在许多细微的错误,它们可能会潜入。就像在哈希中丢失值一样……除非您添加更多并且哈希被重新哈希化,请相信我,那真是个令人讨厌的错误(我失去了价值,直到我向hashMap再添加20个项目,然后突然又出现了)。
- 除非有非常充分的理由修改的对象,返回一个新的对象是最安全的做法。
- 当有是一个很好的理由修改的对象,该修改应该由对象本身(调用方法),而不是通过可玩弄其领域一些外部函数来完成。
- 这允许以较低的维护成本重构对象。
- 这使得对象,以确保该计算其哈希码的值不会改变(或不是其哈希码计算的一部分)
相关:覆盖并返回用作if语句条件的参数的值,在同一if语句内