2012-10-24 22 views
4

我正在研究一个问题,我需要将大量输入加载到问题中,并处理这些输入以创建“问题空间”(即构建允许高效访问输入的数据结构等)。一旦这个初始化完成,一个多线程进程就开始了,它以一种并行的方式广泛地使用了组织/处理过的输入。Java冰棍不可变

出于性能原因,我不想锁定并同步并发阶段中的所有读取操作。我真正想要的是一个不可变的对象,可以安全地同时访问多个阅读器。

出于实际的原因(可读性&可维护性)我不想让InputManager成为一个真正的不可变对象(即所有字段'最终'并在构造中初始化)。 InputManager将有许多数据结构(列表和映射),其中每个对象都有许多循环引用。这些对象被构造为'真实'不可变对象。我不想为InputManager有14个参数的构造函数,但我确实需要InputManager类来构造一个一致的,只读的问题空间视图。

什么我要为是“冰棍不变性”由埃里克利珀讨论here.

我采用的方法依赖于使用“包可见”所有的变异方法,并执行所有可变操作(即InputManager的构建)在一个包中。吸气者都有公众的知名度。

喜欢的东西:

public final class InputManager { // final to prevent making mutable subclasses 
    InputManager() { ... } //package visibility limits who can create one 
     HashMap<String,InputA> lookupTable1; 
     ... 

    mutatingMethodA(InputA[] inputA) { //default (package visibility) 
     //setting up data structures... 
    } 

    mutatingMethodB(InputB[] inputB) { //default (package visibility) 
     //setting up data structures... 
    } 

    public InputA getSpecificInput(String param1) { 
     ... //access data structures 
     return objA; //return immutable object 
    } 
} 

的总体思路,如果我没有得到足够清晰,我会构成输入管理在一个单独的线程,然后将它传递给多个线程谁做的并发使用该对象工作。我希望尽可能强制执行这个“两阶段”可变/不可变对象生命周期,而不要做太“可爱”的事情。寻找更好的方法来实现这个目标的意见或反馈,因为我相信这不是一个不常见的用例,但我找不到支持它的设计模式。

谢谢。

回答

1

就我个人而言,我会保持你的简单和充分的方法,但如果你有兴趣,有这样的事情,如可变伴侣成语。你写了一个内部类有mutators,同时重新使用封闭实例中的所有字段和getter。

只要你失去了可变伴侣,它留下的封闭实例就是真正不可变的。

+0

感谢所有的伟大答案。基于这些答案,我查看了番石榴的ImmutableCollections实现,这里的'builder'范例看起来非常像您提到的可变伴侣成语。我正在研究这个问题,试图决定在这个项目中是否值得在这一点上做出努力。谢谢! – BrianV

+0

这里很好的讨论:(http://codereview.stackexchange.com/questions/11538/comments-on-my-java-pattern-for-mutable-turned-immutable-objects) – BrianV

1

我想你可以简单地为你的两个阶段分开接口。一个用于建筑部分,另一个用于阅读部分。这样,你就可以很干净地分离你的访问模式。您可以将此视为interface segregation principle (pdf)的一个实例:

不应强制客户端依赖于他们不使用的接口。

+1

我喜欢独立接口的想法,并且欣赏指向pdf的指针。谢谢。 – BrianV

+0

@BrianV:不客气! –

1

只要该对象被安全地发布,并且读者不能改变它。

“发布”在这里意味着创作者如何让读者可以使用该对象。例如,创建者将其放入阻止队列中,读者正在轮询队列。

这取决于您的发布方法。我敢打赌这是安全的。

+0

欣赏评论。我会确保发布方法是适当的。 – BrianV