2016-10-29 3 views
1

Я видел много статей, где он говорит, что наследование перерывов инкапсуляцииInhertitance нарушает инкапсуляцию

http://igstan.ro/posts/2011-09-09-how-inheritance-violates-encapsulation.html

Но я не могу понять концепцию позади него. в данном примере

Может кто-нибудь объяснить, как состав избежать этой проблемы

+0

Обернутый 'HashSet' называет свой' add', а не 'add' оболочки. –

ответ

1

В примере в этой статье вы связаны с:

 set.addAll(Arrays.asList("Snap", "Crackle", "Pop")); 

Это вызывает InstrumentedHashSet.addAll.

InstrumentedHashSet.addAll adds 3 to the counter, then calls HashSet.addAll`.

HashSet.addAll звонки this.add три раза, чтобы добавить каждый из элементов.

Но this.add действительно является вызовом для InstrumentedHashSet.add!

Каждый звонок InstrumentedHashSet.add добавляет 1 к счетчику и звонит super.add.

Каждый вызов HashSet.add выполняет фактическую работу по добавлению элемента в набор.

Конечным результатом является то, что мы добавили 6 к счетчику, а не 3, как вы ожидали.

Для правильной реализации InstrumentedHashSet необходимо знать, как реализуется HashSet.addAll, и НЕ увеличивать счетчик в addAll. Но это знание нарушает инкапсуляцию. Подкласс не должен необходимо, чтобы знал, как реализован его суперкласс.


Может кто-нибудь объяснить, как состав избежать этой проблемы

Это позволяет избежать его, потому что, когда HashSet.addAll вызовов this.add, эти призывы к this.add не призывают к InstrumentedHashSet.add. Это прямые звонки на номер HashSet.add.

Фактически, при условии, что HashSet.addAll реализует договор Set.addAll, не имеет значения InstrumentedHashSet, как оно реализовано. Здесь нет нарушения инкапсуляции.

1

Я видел много статей, где он говорит, что наследование перерывов инкапсулирования

http://igstan.ro/posts/2011-09-09-how-inheritance-violates-encapsulation.html

Но я не могу понять концепцию позади него.в данном примере

Может кто-нибудь объяснить, как состав избежать этой проблемы

Слово «разрыв» может быть слишком сильным, но наследование, конечно же, по крайней мере компромиссный инкапсуляцию.

Важной целью инкапсуляции является отделить реализацию API от его контракта. Другими словами, клиенты, которые хотят использовать API, должны понимать только свои «правила дороги» (т. Е. Его контракт), не нуждаясь ни в чем другом в том, как он работает внутри страны. Это позволяет модулям больших систем разделиться и развиваться независимо (при условии, что контракт остается неповрежденным).

К сожалению, когда один класс наследуется от другого, подкласс часто становится зависимым, по крайней мере, от некоторых деталей реализации базового класса ..., который нарушает принцип инкапсуляции.

Есть два распространенных способа, в которых это может произойти:

  • Если подкласс использует метод, унаследованный от базового класса -и- этот метод вызывает другой метод, который является частью экспортируемого API (так «самоиспользование» методов API). Чтобы избежать ошибок, автор подкласса должен знать о самоиспользовании методов базовым классом. Это подробная информация о реализации, которую в противном случае не нужно было бы знать о клиенте API.

  • Защищенные элементы. Иногда подкласс не может реализовать функцию без доступа к данным или поведению из родительского класса. Java предоставляет тип доступа protected, чтобы обеспечить доступ к элементам по подклассам. Таким образом, подкласс имеет непосредственный доступ к информации и методам, которые в противном случае были бы инкапсулированы в родительский класс. Таким образом, подкласс становится зависимым от деталей реализации родителя.

Недостатком того, что детали реализации утечка из вашего класса заключается в том, что правильное использование его больше не зависит только от контракта API. Всякий раз, когда реализация изменяется, есть вероятность, что подклассы будут разбиты.

+0

+1. Я не согласен с вами немного в терминологии, хотя: я бы сказал, что если правильное подклассирование зависит от определенного поведения, то действительно это поведение фактически является частью контракта класса и не является просто детальностью реализации. Но это трудно сделать правильно; гораздо проще (и более естественно) определить контракт для клиентов класса, чем для его подклассов. – ruakh

+0

* «Я бы сказал, что если правильное подклассирование зависит от определенного поведения, то действительно это поведение фактически является частью контракта класса,« * ... no argument. Ключевым моментом здесь является то, было ли это предназначено или нет, поведение * становится * частью экспортированного API. – scottb

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