Часто используется аналогия (в том числе на странице Википедии, как я заметил): вы просите собаку выгуливать - вы спрашиваете собаку, вы не просите доступа к ее ногам, а затем просите ее ноги выгуливать.
Лучше попросить собаку выгуливать, потому что однажды вы можете захотеть собаку с чем-то другим, кроме ног.
В вашем конкретном примере реализация m_A
может перестать зависеть от экземпляра B
.
РЕДАКТИРОВАТЬ: поскольку некоторые люди хотят дальнейшего изложения, позвольте мне попробовать это:
Если объект X
содержит оператор m_A.GetObjectB().DoSomething()
, тогда X
должен знать:
- этот
m_A
имеет экземпляр объекта B
, представленного через GetObject()
; и
- что объект
B
имеет метод DoSomething()
.
Итак, X
необходимо знать интерфейсы A
и B
, а A
всегда иметь возможность продавать B
.
И наоборот, если X
просто нужно было сделать m_A.DoSomething()
, то все, что ему нужно знать, это:
- что
m_A
имеет метод DoSomething()
.
Таким образом, закон способствует разъединению, потому что X
теперь полностью отделен от B
- ему не нужно ничего знать об этом классе - и меньше знаний о A
- он знает, что A
может достичь DoSomething()
, но ему больше не нужно знать, делает ли он это сам или просит ли это сделать кто-то еще.
На практике закон часто не используется, потому что он обычно означает просто написание сотен функций-оболочек, таких как A::DoSomething() { m_B.DoSomething(); }
, а формальная семантика вашей программы часто явно диктует, что A
будет иметь B
, поэтому вы не так сильно раскрываете детали реализации, предоставляя GetObjectB()
поскольку вы просто выполняете контракт этого объекта с системой в целом.
Первый пункт также можно использовать, чтобы утверждать, что закон увеличивает связь. Предположим, у вас изначально было m_A.GetObjectB().GetObjectC().GetObjectD().DoSomething()
, и вы свернули его до m_A.DoSomething()
. Это означает, что, поскольку C
знает, что D
реализует DoSomething()
, C
должен это реализовать. Затем, поскольку B
теперь знает, что C
реализует DoSomething()
, B
должен это реализовать. И так далее. В конце концов, вам нужно A
реализовать DoSomething()
, потому что D
это делает. Итак, A
в конечном итоге вынужден действовать определенным образом, потому что D
действует определенным образом, тогда как раньше он мог ничего не знать о D
.
Во-первых, сравнимая ситуация - методы Java, традиционно объявляющие исключения, которые они могут генерировать. Это означает, что они также должны перечислить исключения, которые все, что они вызывают, может вызвать, если они этого не поймают. Таким образом, каждый раз, когда листовой метод добавляет еще одно исключение, вам нужно пройти вверх по дереву вызовов, добавляя это исключение к целой группе списков. Так что хорошая идея развязки приводит к бесконечной бумажной волоките.
По второму пункту, я думаю, мы заблудились в дебатах «есть» или «есть». «Имеет» - это очень естественный способ выразить некоторые объектные отношения и догматически скрыть это за фасадом типа «У меня есть ключи от шкафчика, поэтому, если вы хотите, чтобы ваш шкафчик открылся, просто подойдите и спросите меня, и я его открою». разговоры просто затмевают задачу.
person
Tommy
schedule
05.07.2013