2012-09-16 32 views
2

对于不可变对象,适合将包含的集合包装为不可修改的地方在哪里?我看到3个选项:不可变对象和不可修改集合

  1. 处于不可改变对象的工厂:

    public class ImmutableFactory { 
    
        public Immutable build(){ 
         List<Integer> values = new ArrayList<Integer>(); 
    
         values.add(1); 
         values.add(2); 
         values.add(3); 
    
         return new Immutable(Collections.unmodifiableList(values), "hello"); 
        } 
    } 
    
  2. 处于不可改变的构造器

    public class Immutable { 
    
        private final List<Integer> values; 
        private final String hello; 
    
        public Immutable(List<Integer> values, String hello) { 
         this.values = Collections.unmodifiableList(values); 
         this.hello = hello; 
        } 
    
        public List<Integer> getValues() { 
         return values; 
        } 
    
        public String getHello() { 
         return hello; 
        } 
    } 
    
  3. 处于不可改变的访问(如适用)。

    public class Immutable { 
    
        private final List<Integer> values; 
        private final String hello; 
    
        public Immutable(List<Integer> values, String hello) { 
         this.values = values; 
         this.hello = hello; 
        } 
    
        public List<Integer> getValues() { 
         return Collections.unmodifiableList(values); 
        } 
    
        public String getHello() { 
         return hello; 
        } 
    } 
    

是否有任何其他选项,哪一个是正确的?

回答

4

如果创建不可变集合,那么你需要保护自己从被指定作为参数来构造有人修改名单我会说,你应该保护性地复制它。

public Immutable(List<Integer> values, String hello) { 
    this.values = Collections.unmodifiableList(new ArrayList<Integer>(values)); 
    this.hello = hello; 
} 

我个人早已切换到Guava集合,因为你可以找到一成不变的集合接口。您的构造函数如下所示:

public Immutable(ImmutableList<Integer> values, String hello) { 
    this.values = values; 
    this.hello = hello; 
} 

您可以确定您收到的参数不会被任何人修改。

它通常是一个好主意,让参考不可变列表的不可变的类中,因为它那么保证你不误修改。在我看来

案例(1)是有道理的,只有当工厂方法是创建不可变集合,即使这样,当有人refactors这些类可能突破的唯一途径。除非有其他限制,否则最好是创建自给自足的课程。

+2

伟大的观点。自从我一直专注于不变性以来,我会给番石榴一枪。 –

+0

如果您有一个返回集合'值'的getter,您会返回一个List或ImmutableList类型吗? –

+1

我只是返回'List'。 (这就是说,番石榴是聪明有关 - 如果你调用'ImmutableList.copyOf'防守这已经不可改变的名单上,它不会实际做的副本,除了在情况下,这将导致内存泄漏。) –

1

首先,你在所有地方的代码确实是不可变的只是因为一个Integer是不可改变的。
如果你有private final List<SomeCustomClass> values;相反,Collections.unmodifiableList(values);不能保证该列表的个别SomeCustomClass是不可改变的。 将不得不为此编码。
话虽如此,另一种选择是做列表的defencive深拷贝。这种方法也提供了不变性。

+0

'List '不支持* class-type项目;它*标识*他们。如果List 不可修改,它将始终标识相同的项目。如果有一个印有十辆车的红色列表,将其中一辆车涂上蓝色不会改变列表。该名单仍然会确定相同的十辆车。同样,List 的状态不会封装其上的项目状态,而仅仅是它们的身份。如果某人正在持有一个私人对象的列表,这些私人对象的状态感兴趣,并且想给某人一个列表... – supercat

+0

...其状态代表第一个列表上的那些快照的对象,则必须将新对象作为快照那些在第一个列表中,并生成一个新的列表来标识这些新的对象。无论是Java还是任何.net语言都允许指定为了封装私有可变对象的状态而持有对象引用。事实上,在封装非共享可变状态,身份,两者或两者之间的变量之间没有区别,这在我看来是一种弱点而不是强度。 – supercat