我answered a question重新设置ImmutableMap
。我建议使用代理模式。
问题是Map
包含put
方法,该方法会抛出UnsupportedOperationException
。用Map
替换ImmutableMap
的其他实例将破坏Liskov替换原则。不仅如此,还需要声明put
和putAll
[违反了接口隔离原则]
从技术上讲,由于Map
只是一个接口,因此无法用ImmutableMap
替换Map
实例。所以我的问题是:
由于ImmutableMap
包含Map
和Map
方法,是否会考虑使用put
接口创建putAll
打破LSP?是否将实现Map
视为“具有不同接口的替代类”的代码味道?如何创建一个遵守LSP但不包含代码味道的ImmutableMap
?
最佳答案
在我看来,ImmutableMap
应该实现Map
。不实现Map
是一个坏主意,因为有许多方法接受Map
作为参数,并且仅在只读意义上使用它。我不认为这确实违反了Liskov替代原则,因为Map
的合同清楚地表明put
是可选操作。
实现Map
的类必须实现put
是不理想的,但替代方法是具有复杂的接口层次结构,每个接口仅包括可能的可选方法的子集。如果有n
可选方法,则必须有2^n
接口才能覆盖所有组合。我不知道n
的值,但是有一些非显而易见的可选操作,例如Iterator
返回的map.entrySet().iterator()
是否支持setValue
操作。如果将此层次结构与实际已经存在的接口和抽象类的层次结构(包括AbstractMap
,SortedMap
,NavigableMap
,ConcurrentMap
,ConcurrentNavigableMap
……)组合在一起,您将一团糟。
因此,对此没有完美的答案,但是我认为最好的解决方案是使ImmutableMap
实现Map
并确保您将Map
作为参数编写的每个方法清楚地记录了Map
必须具有的所有属性以及如果错误则抛出的异常传递了Map
类型。