我有一个复杂的对象,它保存在内存中,不应该被修改。它用作模板,其中一些字段在首次实例化时初始化,一些字段在运行时根据一些调用代码参数确定和更新。
考虑这个例子:
FooTemplate是一个加载到内存中的对象。调用代码需要此对象的更新版本。更新后的版本有一个填充的服务中心列表。列表的内容取决于客户端代码中的一些参数,在这种情况下是调用者的国家。
public class FooTemplate {
private final String companyName;
private final String identifier;
private final List<String> serviceCenters = new ArrayList<String>();
public FooTemplate(String companyName, String identifier) {
this.companyName = companyName;
this.identifier = identifier;
}
public String getCompanyName() {
return companyName;
}
public String getIdentifier() {
return identifier;
}
public List<String> getServiceCenters() {
return serviceCenters;
}
@Override
public String toString() {
return "FooTemplate [companyName=" + companyName + ", identifier="
+ identifier + ", serviceCenters=" + serviceCenters + "]";
}
}
FooManager是一个加载FooTemplate对象的单例:
public class FooManager {
private static final FooManager fooManager = new FooManager();
private FooTemplate fooTemplate;
private FooManager() {
this.fooTemplate = new FooTemplate("ABC inc.", "93746789");
}
public static FooManager getInstance() {
return fooManager;
}
public FooTemplate getFoo() {
return fooTemplate;
}
}
这是测试类:
class Test {
public static void main(String[] args) {
Caller[] callers = {new Caller (CountryCode.US),
new Caller (CountryCode.US),
new Caller (CountryCode.US)};
for (int i = 0; i < callers.length; i++){
System.out.println(getFoo(callers[i]));
}
}
public static FooTemplate getFoo(Caller caller) {
FooManager fooManager = FooManager.getInstance();
FooTemplate fooTemplate = fooManager.getFoo();
if (caller.getCountryCode() == CountryCode.US){
fooTemplate.getServiceCenters().add("Seattle");
fooTemplate.getServiceCenters().add("Boston");
}
if (caller.getCountryCode() == CountryCode.GER){
fooTemplate.getServiceCenters().add("Munich");
fooTemplate.getServiceCenters().add("Berlin");
}
if (caller.getCountryCode() == CountryCode.FRA){
fooTemplate.getServiceCenters().add("Paris");
fooTemplate.getServiceCenters().add("Lyon");
}
return fooTemplate;
}
}
它产生以下输出:
FooTemplate [companyName = ABC inc。,identifier = 93746789,serviceCenters = [Seattle,Boston]]
FooTemplate [companyName = ABC inc。,identifier = 93746789,serviceCenters = [Seattle,Boston,Seattle,Boston]]
FooTemplate [companyName = ABC inc。,identifier = 93746789,serviceCenters = [Seattle,Boston,Seattle,Boston,Seattle,Boston]]
我理解这种情况正在发生,因为每次迭代都会修改相同的对象。我是否需要在修改对象之前对其进行深层复制并返回副本,还是有更好的解决方案?
编辑: 在实际代码中,模板对象是通过解析xml创建的,解析只在单例中完成一次。这就是我每次需要时都无法创建新模板对象的原因。
答案 0 :(得分:0)
每次拨打FooTemplate
时,您都可以创建getFoo
的新实例。
public static FooTemplate getFoo() {
return new FooTemplate("ABC inc.", "93746789");
}
或者,如果您不想创建过多companyName
和identifier
,请考虑致电String.intern()
。 (我认为编译器无论如何都会优化内存分配。)
如果两个字符串在整个程序中都是常量,请考虑将它们声明为static final
。
一般情况下,从头开始创建对象时,从另一个对象复制对象并不是一个好习惯。
编辑:
只需创建一个新类FooCompany
。
public class FooCompany {
private final String companyName;
private final String identifier;
public FooCompany(String companyName, String identifier) {
this.companyName = companyName;
this.identifier = identifier;
}
public String getCompanyName() {
return companyName;
}
public String getIdentifier() {
return identifier;
}
}
public class FooManager {
private static final FooManager fooManager = new FooManager();
private FooCompany fooCompany;
private FooManager() {
this.fooCompany = new FooCompany("ABC inc.", "93746789");
}
public static FooManager getInstance() {
return fooManager;
}
public FooTemplate getFoo() {
return new FooTemplate(fooCompany.getCompanyName(), fooCompany.getIdentifier());
}
}
答案 1 :(得分:0)
//您可以使用以下代码替换FooManger
public class FooManager {
private static final FooManager fooManager = new FooManager();
//if company and contact are fix, make them final
private final String COMPANY="ABC inc.";
private final String CONTACT="93746789";
private FooManager() {
}
public static FooManager getInstance() {
return fooManager;
}
public FooTemplate getFoo() {
return new FooTemplate(COMPANY, CONTACT);
}
}