1

我有一个接受对象并对其进行处理的例程。对象可能是可变的,也可能不是可变的。

void CommandProcessor(ICommand command) {
    // do a lot of things
}

相同的命令实例有可能在处理器中循环返回。当这种情况发生时,事情会变得很糟糕。我想检测这些回访者并阻止他们被处理。问题是我怎样才能透明地做到这一点,即不干扰对象本身。

这是我尝试过的

  • Boolean Visited {get, set}ICommand. _

我不喜欢这样,因为一个模块的逻辑出现在另一个模块中。ShutdownCommand与关闭有关,而不是与簿记有关。还有一个EatIceCreamCommand可能总是回来False,希望得到更多。一些非可变对象在设置器方面存在明显问题。

  • 私下维护所有已处理实例的查找表。当一个对象首先检查列表时。

我也不喜欢这个。(1)性能。查找表变大。我们需要做线性搜索来匹配实例。(2) 不能依赖hashcode。该对象可能会不时伪造不同的哈希码。(3) 将对象保存在列表中可以防止它们被垃圾收集。

我需要一种方法在只有我的代码才能看到的实例(ICommand)上放置一些不可见的标记。目前我不区分调用。只是祈祷同样的情况不要回来。有没有人有更好的想法来实现这个功能..?

4

1 回答 1

3

假设您无法从逻辑上阻止这种情况的发生(尝试切断循环),我会选择HashSet您已经看过的命令。

即使对象违反了HashCodeand的合同Equals(我认为这是一个开始的问题),您也可以创建自己的IEqualityComparer<ICommand>用于非虚拟System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode调用的对象。Object.GetHashCodeEquals方法只会测试参考身份。因此,您的池将包含不同的实例,而不关心命令是否或如何覆盖EqualsGetHashCode.

这只是留下了堆积垃圾的问题。假设您没有定期清除池的选项,您可以使用WeakReference<T>(或 .NET 4 的非泛型WeakReference类)来避免保留对象。然后,您会经常发现所有“死”的弱引用,以防止甚至累积这些引用。IEqualityComparer<WeakReference<T>>(在这种情况下,您的比较器实际上是一个,比较弱引用的目标以获得身份。)

它不是特别优雅,但我认为这是设计中固有的——你需要处理一个命令来改变某处的状态,一个不可变的对象不能根据定义改变状态,所以你需要命令之外的状态。哈希集似乎是一种相当合理的方法,希望我已经说明了如何避免您提到的所有三个问题。

编辑:我没有考虑过的一件事是 usingWeakReference<T>使得很难删除条目 - 当原始值被垃圾收集时,您将无法再找到它的哈希码。您可能只需要HashSet使用仍然存在的条目创建一个新条目。或者使用您自己的 LRU 缓存,如评论中所述。

于 2013-06-15T08:12:12.213 回答