在聚合 class 中使用克隆的最佳实践
The best practice using clone in an aggregated class
我有一个系统,其中有一个客户,其属性为补充剂的 ArrayList。
客户 class 的代码是:
public class Customer implements Cloneable
{
.
.
ArrayList<Supplement> suppList
public Customer(String fName, String lName, String emailInput, ArrayList<Supplement> list)
{
setFName(fName);
setLName(lName);
setEmailAddr(emailInput);
setSuppList(list);
}
public void setSuppList(ArrayList<Supplement> list)
{
suppList = new ArrayList<Supplement>();
for(Supplement sp : list)
{
suppList.add(sp);
}
}
}
public ArrayList<Supplement> getSuppList() throws CloneNotSupportedException
{
ArrayList<Supplement> list = new ArrayList<Supplement>();
if (suppList != null)
{
for(Supplement sp : suppList)
{
list.add((Supplement)sp.clone());
}
}
return list;
}
public void addSupp(Supplement item)
{
suppList.add(item);
}
public void removeSupp(Supplement item)
{
suppList.remove(item);
}
最初,我的 setSuppList 方法只包含一行代码,即 suppList = list,而我的 getSuppList 方法只是 'return suppList'。
我觉得这是一种隐私泄露,所以我在这两种方法上都调用了克隆。
对于 setSuppList,suppList = new ArrayList() 并遍历参数列表并克隆每个对象并将其添加到 suppList 数组中。
对于 getSuppList,它遍历 suppList 并克隆其中的每个 Supplement 对象,将其添加到新数组和 return 数组中。
但是,我意识到如果将补充对象价格从 3 美元更改为 50 美元,并且如果我有 100 个客户,则意味着我必须继续调用 setSuppList() 100x。
我改变了主意,所以我将 setSuppList 方法更改为 suppList = list 并将克隆内容仅保留在 getSuppList 中。
然后我想到了...为什么不将 suppList 作为 setSuppList 中的新数组并将参数 'list' 中的每个项目添加到 suppList。
这样,list 和 suppList 都引用相同的对象
但是当列表删除一个项目时,Customer 对象的 suppList 不受影响。
只是当单个项目受到影响时,suppList 相应地更新(例如补充剂的价格)
当我想在 suppList 中添加或删除一个项目时,我可以使用 addSupp 方法或 removeSupp 方法,或 setSuppList 方法。
public static void main(String[] args)
{
try
{
Supplement s1 = new Supplement("A", 2.9);
Supplement s2 = new Supplement("B", 3);
ArrayList<Supplement> spList = new ArrayList<Supplement>();
spList.add(s1);
spList.add(s2);
Customer cstmr = new Customer("killua", "zoldyck", "killua@gmail.com", spList);
ArrayList<Supplement> spList2 = cstmr.getSuppList();
System.out.println("cloned array size : "+spList2.size());
spList2.remove(0);
System.out.println("After removing an item in the cloned array");
System.out.println("cloned array size : "+spList2.size());
System.out.println("Array returned from getSuppList size : "+cstmr.getSuppList().size());
spList.remove(0);
System.out.println("array size : "+cstmr.getSuppList().size());
System.out.println("");
spList.get(0).setWeeklyCost(50);
System.out.println("If I change the first item in the first array prize to 50");
System.out.println("price of 1st item in object in the first array : "+spList.get(0).getWeeklyCost());
System.out.println("price of 1st item in object in the array returned by getSuppList : "+cstmr.getSuppList().get(0).getWeeklyCost());
System.out.println("");
s1.setWeeklyCost(40);
System.out.println("If I change the supplement object directly to 40");
System.out.println("price of 1st item in object in the first array : "+spList.get(0).getWeeklyCost());
System.out.println("price of 1st item in object in the array returned by getSuppList : "+cstmr.getSuppList().get(0).getWeeklyCost());
}
catch(CloneNotSupportedException e)
{
}
}
输出
克隆数组大小:2
删除克隆数组中的项目后
克隆数组大小:1
数组 return 来自 getSuppList 大小:2
数组大小:2
如果我将第一个数组奖品中的第一项更改为 50
第一个数组中对象中第一项的价格:50.0
数组中对象中第一项的价格 return由 getSuppList 编辑:2.9
如果我直接把补充对象改成40
第一个数组中对象中第一项的价格:50.0
数组中对象中第一项的价格 return由 getSuppList 编辑:40.0
但是,当我尝试这样做时,出现了意外行为。 spList.get(0).setWeeklyCost(50);不影响客户对象的 suppList 对象。
怎么可能? spList 和 suppList 都引用相同的对象,尽管它们是不同的数组...
由于 Supplement
是它自己的东西,与 Customer
完全不同,并且可以自行重命名和重新定价,因此您永远不应将其克隆为 Customer
逻辑的一部分。
你应该 "clone" list,因为那是一个 属性 的客户,这很容易通过调用 copy-constructor :
suppList = new ArrayList<>(list);
spList.get(0).setWeeklyCost(50); does not affect the suppList object of a Customer object. How can it be ??
因为当你调用cstmr.getSuppList()
时你还在克隆Supplement
我有一个系统,其中有一个客户,其属性为补充剂的 ArrayList。
客户 class 的代码是:
public class Customer implements Cloneable
{
.
.
ArrayList<Supplement> suppList
public Customer(String fName, String lName, String emailInput, ArrayList<Supplement> list)
{
setFName(fName);
setLName(lName);
setEmailAddr(emailInput);
setSuppList(list);
}
public void setSuppList(ArrayList<Supplement> list)
{
suppList = new ArrayList<Supplement>();
for(Supplement sp : list)
{
suppList.add(sp);
}
}
}
public ArrayList<Supplement> getSuppList() throws CloneNotSupportedException
{
ArrayList<Supplement> list = new ArrayList<Supplement>();
if (suppList != null)
{
for(Supplement sp : suppList)
{
list.add((Supplement)sp.clone());
}
}
return list;
}
public void addSupp(Supplement item)
{
suppList.add(item);
}
public void removeSupp(Supplement item)
{
suppList.remove(item);
}
最初,我的 setSuppList 方法只包含一行代码,即 suppList = list,而我的 getSuppList 方法只是 'return suppList'。 我觉得这是一种隐私泄露,所以我在这两种方法上都调用了克隆。 对于 setSuppList,suppList = new ArrayList() 并遍历参数列表并克隆每个对象并将其添加到 suppList 数组中。 对于 getSuppList,它遍历 suppList 并克隆其中的每个 Supplement 对象,将其添加到新数组和 return 数组中。 但是,我意识到如果将补充对象价格从 3 美元更改为 50 美元,并且如果我有 100 个客户,则意味着我必须继续调用 setSuppList() 100x。
我改变了主意,所以我将 setSuppList 方法更改为 suppList = list 并将克隆内容仅保留在 getSuppList 中。
然后我想到了...为什么不将 suppList 作为 setSuppList 中的新数组并将参数 'list' 中的每个项目添加到 suppList。 这样,list 和 suppList 都引用相同的对象 但是当列表删除一个项目时,Customer 对象的 suppList 不受影响。 只是当单个项目受到影响时,suppList 相应地更新(例如补充剂的价格) 当我想在 suppList 中添加或删除一个项目时,我可以使用 addSupp 方法或 removeSupp 方法,或 setSuppList 方法。
public static void main(String[] args)
{
try
{
Supplement s1 = new Supplement("A", 2.9);
Supplement s2 = new Supplement("B", 3);
ArrayList<Supplement> spList = new ArrayList<Supplement>();
spList.add(s1);
spList.add(s2);
Customer cstmr = new Customer("killua", "zoldyck", "killua@gmail.com", spList);
ArrayList<Supplement> spList2 = cstmr.getSuppList();
System.out.println("cloned array size : "+spList2.size());
spList2.remove(0);
System.out.println("After removing an item in the cloned array");
System.out.println("cloned array size : "+spList2.size());
System.out.println("Array returned from getSuppList size : "+cstmr.getSuppList().size());
spList.remove(0);
System.out.println("array size : "+cstmr.getSuppList().size());
System.out.println("");
spList.get(0).setWeeklyCost(50);
System.out.println("If I change the first item in the first array prize to 50");
System.out.println("price of 1st item in object in the first array : "+spList.get(0).getWeeklyCost());
System.out.println("price of 1st item in object in the array returned by getSuppList : "+cstmr.getSuppList().get(0).getWeeklyCost());
System.out.println("");
s1.setWeeklyCost(40);
System.out.println("If I change the supplement object directly to 40");
System.out.println("price of 1st item in object in the first array : "+spList.get(0).getWeeklyCost());
System.out.println("price of 1st item in object in the array returned by getSuppList : "+cstmr.getSuppList().get(0).getWeeklyCost());
}
catch(CloneNotSupportedException e)
{
}
}
输出
克隆数组大小:2
删除克隆数组中的项目后
克隆数组大小:1
数组 return 来自 getSuppList 大小:2
数组大小:2
如果我将第一个数组奖品中的第一项更改为 50
第一个数组中对象中第一项的价格:50.0
数组中对象中第一项的价格 return由 getSuppList 编辑:2.9
如果我直接把补充对象改成40
第一个数组中对象中第一项的价格:50.0
数组中对象中第一项的价格 return由 getSuppList 编辑:40.0
但是,当我尝试这样做时,出现了意外行为。 spList.get(0).setWeeklyCost(50);不影响客户对象的 suppList 对象。
怎么可能? spList 和 suppList 都引用相同的对象,尽管它们是不同的数组...
由于 Supplement
是它自己的东西,与 Customer
完全不同,并且可以自行重命名和重新定价,因此您永远不应将其克隆为 Customer
逻辑的一部分。
你应该 "clone" list,因为那是一个 属性 的客户,这很容易通过调用 copy-constructor :
suppList = new ArrayList<>(list);
spList.get(0).setWeeklyCost(50); does not affect the suppList object of a Customer object. How can it be ??
因为当你调用cstmr.getSuppList()
Supplement