2015-04-25 2 views
3

I answered a question regaurding a ImmutableMap. Я предложил использовать шаблон прокси.Как написать ImmutableMap, который следует за подпиской Лискова и другими принципами SOLID без запаха кода?

Проблема заключается в том, что Map содержит метод put, который бы выбрал UnsupportedOperationException. Замена других экземпляров Map на ImmutableMap приведет к нарушению принципа «Подписки» Лискова. Мало того, что необходимо объявить put и putAll [нарушает принцип сегрегации интерфейс]

Технически, нет никакого способа, чтобы заменить Map экземпляр с ImmutableMap, поскольку Map просто интерфейс. Так что мой вопрос:

Would создание ImmutableMap с помощью интерфейса Map считается нарушением LSP, поскольку Map содержит метод put и putAll? Не будет ли реализация Map рассматриваться как «альтернативный класс с разными интерфейсами»? Как создать ImmutableMap, который находится в LSP еще не содержит запахов кода?

+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) (также как 'remove' и' clear') определяются как «необязательные операции». Кроме того, возможность указания класса UnsupportedOperationException из классов реализуется в документации по интерфейсу. –

+0

@MickMnemonic Но это нарушает принцип разделения интерфейса [http://en.m.wikipedia.org/wiki/Interface_segregation_principle), в котором говорится: «* ни один клиент не должен зависеть от методов, которые он не использует *».Я отредактирую вопрос, включив его в то, что он должен следовать другим принципам SOLID, а также –

+3

. Мое мнение заключалось в том, что контракты на эти методы мутации, по крайней мере, хорошо документированы в интерфейсе «Карта». Но у вас очень важный момент; интерфейс «Карта» - это _fat_. Возможно, это должно было быть разделено на «Map» и «ModifiableMap extends Map», изначально. –

ответ

1

На мой взгляд, ImmutableMap должен реализовать Map. Было бы плохой идеей не реализовывать Map, так как существует множество методов, которые принимают аргумент Map и используют его только в режиме «только для чтения». Я не считаю, что это нарушает принцип подписки Лискова, поскольку контракт на Map дает понять, что put является дополнительной операцией.

Это не так, что классы, реализующие Map, должны реализовать put, но альтернативой было бы иметь сложную иерархию интерфейсов, каждая из которых включала бы только подмножество возможных дополнительных методов. Если есть необязательные методы n, для всех комбинаций должны быть интерфейсы 2^n. Я не знаю значения n, но есть некоторые неочевидные дополнительные операции, такие как: Iterator, возвращенный map.entrySet().iterator(), поддерживает операцию setValue. Если вы объединили эту иерархию с иерархией интерфейсов и абстрактных классов, которые на самом деле уже существуют (в том числе AbstractMap, SortedMap, NavigableMap, ConcurrentMap, ConcurrentNavigableMap ...), у вас будет полный беспорядок.

Так что нет идеального ответа на этот вопрос, но на мой взгляд, лучшим решением будет сделать ImmutableMap реализовать Map и убедитесь, что каждый метод вы пишете с Map в качестве аргумента четко описаны все свойства Map должны иметь и исключения если неправильный тип Map передан.

+1

Иерархия интерфейсов будет придерживаться принципа разделения сегрегации; Я бы предпочел много интерфейсов для одного громоздкого. Я могу вспомнить несколько случаев, когда «Карта» мутировалась, но вы правы; в большинстве случаев речь идет только о доступе (по крайней мере, в ситуациях, общих для меня). Я не собираюсь лгать, я уже понял такой ответ; Я действительно надеялся на какой-то «скрытый камень», который мог бы помочь мне решить эту ситуацию. Я буду ждать немного больше для получения дополнительных ответов перед тем, как принять; Надеюсь, вы понимаете. Если никто не появится, вы получите мой голос из-за вашего успокаивающего заявления :) –

Смежные вопросы