В примере в статье, на которую вы ссылаетесь:
set.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
Это вызывает InstrumentedHashSet.addAll
.
InstrumentedHashSet.addAlladds 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
не имеет значения, как он реализован. Здесь нет нарушения инкапсуляции.
29.10.2016