2015-04-25 32 views
3

answered a question regaurding一ImmutableMap。我建议使用代理模式。如何编写一个不带代码味道的遵循Liskov置换和其他SOLID原则的ImmutableMap?

问题在于Map包含put方法,该方法会抛出UnsupportedOperationException。用ImmutableMap代替Map的其他实例将打破Liskov的替代原则。不仅如此,需要申报putputAll [违反接口隔离原则]

从技术上讲,是没有办法用ImmutableMap更换Map例如,由于Map是一个简单的接口。所以我的问题是:

将使用Map接口被认为是打破了LSP创建ImmutableMap,因为Map包含putputAll方法?不会执行Map被认为是“具有不同接口的替代类”的代码味道?如何创建一个遵循LSP但不包含代码异味的ImmutableMap

+2

['Map.put'](http://docs.oracle.com/javase/7/docs/api/java/util/Map.html?is-external=true#put%28K,%20V% 29)和['Map.putAll'](http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#putAll%28java.util.Map%29)(以及作为“删除”和“清除”)被定义为“可选操作”。此外,在接口文档中指定了从实现类抛出UnsupportedOperationException的可能性。 –

+0

@MickMnemonic但是这违反了[接口隔离原则](http://en.m.wikipedia.org/wiki/Interface_segregation_principle),其中声明“*不应强迫客户端依赖于它不使用的方法*”。我将编辑该问题,以包括它应该遵循其他SOLID原则 –

+3

我的观点是,这些变异方法的契约至少在'Map'接口中有很好的记录。但你有一个非常有用的观点; 'Map'接口是_fat_之一。也许它本来应该被拆分成'Map'和'ModifiableMap extends Map'。 –

回答

1

在我看来,ImmutableMap应该实现Map。由于有许多方法接受Map作为参数,并且仅以只读方式使用它,因此不实施Map是个坏主意。我不认为这确实违反了利斯科夫替代原则,因为Map的合同明确指出put是一项可选的操作。

实现Map的类不得不实现put,但替代方案将具有复杂的接口层次结构,每个接口层次只包含可能的可选方法的子集。如果有可选方法,则必须有2^n接口来覆盖所有组合。我不知道n的值,但有一些非明显的可选操作,例如map.entrySet().iterator()返回的Iterator是否支持setValue操作。如果您将此层次结构与实际已存在的接口和抽象类的层次结合在一起(包括AbstractMapSortedMap,NavigableMap,ConcurrentMap,ConcurrentNavigableMap ...),您将会一团糟。

所以没有完美的答案,但在我看来,最好的解决办法是让ImmutableMap实施Map并确保每一个方法,你有Map写作为参数清晰地记录了任何性质的Map必须具备的例外如果错误类型Map通过,则抛出。

+1

接口层次结构将遵循接口隔离原则;我更喜欢很多接口到一个庞大的接口。我可以想到一些“Map”变异的情况,但你是对的;大多数情况下只涉及访问(至少在我的情况下)。我不会说谎,我已经想出了这样一个答案;我真的希望有某种“隐藏的宝石”可以帮助我解决这种情况。在接受之前,我会再等一等以获得更多答案;我希望你明白。如果没有出现,你会得到我的投票,因为你的平静声明:) –

相关问题