0

我遇到了一个非常讨厌的我会说'副作用',但这显然是一个糟糕的设计问题。我正在使用 Guava ForwardingList模式来装饰常规列表。我的目的是建立一个大小限制列表,其中最旧的元素在满足 maximumSize 时被踢出(一个简单的 FIFO 设计)。请注意,我不会代理或克隆我现有的收藏。但我有这个非常讨厌的副作用:

List<String> originalList = new ArrayList<String>();
int maximumSize = 2;

originalList.add("foo");
originalList.add("bar");

System.out.println(originalList); // [foo, bar]

ListFactory<String> factory = ListFactory.getInstance(String.class);
List<String> decoratedList = factory.newTalendList(originalList, maximumSize);

decoratedList.add("beer");
System.out.println(originalList); // [bar, beer]

originalList.add("ben");
System.out.println(originalList); // [bar, beer, ben] <-- !!!
System.out.println(decoratedList); // [bar, beer, ben] <-- !!!

(注意:我的装饰类覆盖 add() 以在添加新元素时删除列表的第一个元素。所有其他非覆盖方法,包括 toString(),都委托给原始列表)

好的,您可能会看到,如果我使用原始的 add() 方法添加元素,我可能会超过最大尺寸...好吧,我想这是不可避免的(毕竟这在设计上并没有错)。但这对于 decoratedList 的设计并非如此。

我发现的唯一解决方法是:

List<String> decoratedList = factory.newTalendList(new ArrayList<String>(originalList), maximumSize);

但这似乎不是最好的方法(我不确定它是否适用于所有情况):我不是在装饰originalList,而是她的匿名克隆!我想知道:也许我完全搞砸了我的设计?有没有更好的方法来构建它?

4

2 回答 2

9

这种模式起作用的唯一方法是originalList在创建装饰器后不再引用。ForwardingList不可能originalList控制. (没有装饰器可以。)

总的来说,您可能应该的是创建一个工厂方法,该方法返回一个全新的装饰列表,并且根本不允许您访问原始列表。

于 2012-12-13T23:38:17.717 回答
1

您尝试做的事情非常奇怪。原始列表对被约束一无所知,约束列表也认为他是唯一使用原始列表的人。因此,请不要以可能会弄乱其装饰版本的方式使用原始列表。

于 2012-12-13T23:39:32.480 回答