Java 在聚合类中使用克隆的最佳实践

Java 在聚合类中使用克隆的最佳实践,java,clone,Java,Clone,我有一个系统,其中有一个客户,其属性是补充剂的数组列表 客户类别的代码为: public class Customer implements Cloneable { . . ArrayList<Supplement> suppList public Customer(String fName, String lName, String emailInput, ArrayList<Supplement> list

我有一个系统,其中有一个客户,其属性是补充剂的数组列表

客户类别的代码为:

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);
    }
公共类客户实现可克隆
{
.
.
ArrayList支持列表
公共客户(字符串fName、字符串lName、字符串emailInput、ArrayList列表)
{
setFName(fName);
setLName(lName);
setEmailAddr(emailInput);
设置支持列表(列表);
}
公共无效设置列表(ArrayList列表)
{
suppList=newarraylist();
用于(补充sp:列表)
{
添加(sp);
}
}
}
public ArrayList getSuppList()引发CloneNotSupportedException
{
ArrayList=新建ArrayList();
if(suppList!=null)
{
对于(补充sp:供应清单)
{
添加((补充)sp.clone());
}
}
退货清单;
}
公共无效添加支持(补充项)
{
供应清单。添加(项目);
}
公共无效删除支持(补充项)
{
供应清单。删除(项目);
}
最初,我的setSuppList方法只包含一行代码,即suppList=list,而我的getSuppList方法只是“return suppList”。 我觉得这是一个隐私泄露,所以我在两种方法上都称之为克隆。 对于setSuppList,suppList=new ArrayList(),它遍历参数列表,克隆每个对象并将其添加到suppList数组中。 对于getSuppList,它迭代suppList并克隆其中的每个补充对象,将其添加到新数组中并返回数组。 但是,我意识到,如果将一个补充对象的价格从3美元更改为50美元,并且如果我有100个客户,这意味着我必须继续调用setSuppList()100x

我改变了主意,所以我将setSuppList方法更改为suppList=list,并将克隆内容仅保留在getSuppList中

然后我想到。。。为什么不在setSuppList中将suppList设置为一个新数组,并将参数“list”中的每一项添加到suppList中呢。 这样,list和suppList都引用相同的对象 但是,当列表删除一个项目时,Customer对象的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)
{

}
publicstaticvoidmain(字符串[]args)
{
尝试
{
补编s1=新补编(“A”,2.9);
补编s2=新补编(“B”,3);
ArrayList spList=新的ArrayList();
spList.add(s1);
spList.add(s2);
客户cstmr=新客户(“killua”、“zoldyck”、”killua@gmail.com“,spList);
ArrayList spList2=cstmr.getSuppList();
System.out.println(“克隆数组大小:+spList2.size());
spList2.删除(0);
System.out.println(“删除克隆数组中的项后”);
System.out.println(“克隆数组大小:+spList2.size());
System.out.println(“从getSuppList size返回的数组:+cstmr.getSuppList().size());
spList.remove(0);
System.out.println(“数组大小:+cstmr.getSuppList().size());
System.out.println(“”);
spList.get(0.setWeeklyCost(50);
System.out.println(“如果我将第一个数组中的第一个项目更改为50”);
System.out.println(“第一个数组中对象中第一项的价格:”+spList.get(0.getWeeklyCost());
System.out.println(“getSuppList返回的数组中对象中第一项的价格:”+cstmr.getSuppList().get(0.getWeeklyCost());
System.out.println(“”);
s1.设置每周成本(40);
System.out.println(“如果我将补充对象直接更改为40”);
System.out.println(“第一个数组中对象中第一项的价格:”+spList.get(0.getWeeklyCost());
System.out.println(“getSuppList返回的数组中对象中第一项的价格:”+cstmr.getSuppList().get(0.getWeeklyCost());
}
捕获(CloneNotSupportedException e)
{
}
}

输出

克隆阵列大小:2

删除克隆阵列中的项后

克隆数组大小:1

从getSuppList返回的数组大小:2

阵列大小:2

如果我将第一个阵列中的第一个项目更改为50

第一个数组中对象中第一项的价格:50.0

getSuppList返回的数组中对象中第一项的价格:2.9

如果我直接将补充对象更改为40

第一个数组中对象中第一项的价格:50.0

getSuppList返回的数组中对象中第一项的价格:40.0

然而,当我尝试这样做时,出现了一种意想不到的行为。spList.get(0.setWeeklyCost(50);不影响客户对象的suppList对象


这怎么可能?spList和suppList都引用相同的对象,尽管它们是不同的数组…

因为
增补
是它自己的东西,与
客户
完全不同,并且可以自己重命名和重新定价,所以绝不能将其克隆为
客户
逻辑的一部分

您应该“克隆”列表,因为这是客户的属性,通过调用复制构造函数可以轻松完成:

suppList = new ArrayList<>(list);
suppList=newarraylist(列表);
spList.get(0.setWeeklyCost(50);不影响客户对象的suppList对象。怎么可能呢


由于调用
cstmr.getSuppList()

时您仍在克隆
Supplement
,因为
Supplement
是它自己的东西,与
Customer
完全不同,并且可以自己重命名和重新定价,所以您不应该将其克隆为
Customer
逻辑的一部分

您应该“克隆”列表,因为这是客户的属性,通过调用复制构造函数可以轻松完成:

suppList = new ArrayList<>(list);
suppList=newarraylist(列表);