将对象传递给Method并更改属性

时间:2014-12-10 13:31:33

标签: java parameter-passing

如果我有一个如下所示的课程:

class A {
   private List<B> bs = new ArrayList<B>;

   public List<B> getBs() {
    return bs;
   }
}

它包含B类型的对象列表。

另一个类使用此列表并将列表中的一个Object交给另一个C类对象:

class SomeOtherClass {

   private C c;

   public void someMethod() {
   //code...
   ArrayList<B> bs = mA.getBs();
   c.setB(bs.get(0));

   }

}

最后,对象b的成员字段的某些值会发生变化。

class C {
    private B b;

    public void setB(B b) {
       this.b = b;
       this.b.ChangeValue();
    }
}

这种方式当然会修改原始列表中的对象,这就是我想要的。 但是,我发现C类修改了类A的列表bs中的对象的值非常令人困惑。对于另一个开发人员,很难看到此方法更改了值。 所以我认为我在这里做的事情被认为是不好的做法,不是吗?` 编写此类代码的更好方法是什么?

3 个答案:

答案 0 :(得分:1)

我同意你的推理。这个方法:

public void setB(B b) {
    this.b = b;
    this.b.ChangeValue();
}

实施得不是很好。它最好应该重构。如果这不是一个选项,它应该清楚地记录传递给方法时B参数被修改。如果可能,也应该从方法名称中明确这一点。也许您可以将其命名为setAndUpdate(B b)


此方法:

class A {
    private List<B> bs = new ArrayList<B>;

    public List<B> getBs() {
        return bs;
    }
}

可能可以接受:

  • 如果A的接口应该允许插入和删除B个对象,我会说可以分发支持列表以利用列表操作方法,例如{ {1}},addAll等由clear提供。

  • 如果List确实属于bs内部状态,而A则涉及A的修改(例如,如果需要维护一些涉及bs的不变量,那么它应该泄漏支持数据结构。

您可以在标准集合API中找到这两种变体的示例。例如,bskeySet会公开影响从中检索地图的集合。另一方面,entrySet会返回一份副本。

如果要公开支持列表的只读版本,可以执行

List.toArray

答案 1 :(得分:1)

  

我认为我在这里做的事情被认为是不好的做法,不是吗?

是的,通过getter暴露你的类的可变部分可能会产生误导,因为数据封装得不够好。更改数据没有任何问题,只是它以一种不会立即脱颖而出的方式完成。

没有通用的规则来解决这个问题。通常,您应该避免直接在类中返回可变对象。相反,请在适当的位置提供getter和setter,并且不要向调用者提供List<B>

class A {
     private List<B> bs = new ArrayList<B>;

     public void getSizeB() {
         return bs.size();
     }
     public B getB(int i) {
         return bs.get(i);
     }
     public void setB(int i, B b) {
         bs.set(i, b);
     }
     public void addB(B b) {
         bs.add(B);
     }
     ... // Add more methods as needed
}

我们的想法是控制进入List<B>的内容:由于没有直接访问权限,您可以验证进入列表的每个B。使用您的类A的代码必须明确说明它所做的所有修改,因为它无法直接获取列表并随意执行任何操作。

答案 2 :(得分:1)

首先,我要说getBs()是一个坏主意,因为该方法的调用者可以清除列表或向其添加元素,这对{的状态更为严重。 {1}}而不仅仅是更改列表中某个元素的属性。

您可以将其替换为A,它返回该列表的第i个元素。 现在,如果getB(int)是不可变的,那么您的工作就完成了,B的调用者无法更改A状态中的任何内容。

如果B是可变的,您可以决定getB(int)会返回getB(int)的副本。

总结一下,我会替换:

bs.get(i)

使用

public void getBs() {
    return bs;
}

public void getB(int i) {
    return bs.get(i);
}

当然,您还应该添加范围检查,以确保public void getB(int i) { return new B(bs.get(i)); } 是有效的索引。