2.24 Зависимости между модулями

Композиция (как и программирование вообще) — дело непростое. Одни модули используют другие, из-за чего возникают сложные зависимости. И вот уже программное обеспечение нельзя рассматривать как набор модулей, поскольку это монолит, собранный из того, что замышлялось как модули, и обвязанный вокруг зависимостями, при этом ни один модуль не может работать без других.

Модифицировать такую программное обеспечение не просто трудно, а невозможно.

Для борьбы с этим явлением существует несколько методов. Один из них называется законом Деметры (не имеет прямого отношения к богине плодородия, просто так назывался проект, в котором развилась эта техника), он формулируется так: «Never talk to strangers» — «Никогда не разговаривайте с неизвестными».

Смысл закона Деметры в том, что длинные вызовы вроде a.getB().getC().getD( ).doE() вредят структуре системы. Проектировать классы нужно так, чтобы вызовы были не длиннее, чем a.doB(), где а — элемент текущего объекта. Это радикальное правило. Проектировать системы таким образом сложно, хотя возможно. К этому правилу следует относиться как к рекомендации.

Гораздо более действенное правило формулируется как «Low coupling, high cohesion» — «Низкая связность, высокое зацепление». Каждый модуль должен быть связным (логически единым) — элементы внутри модуля должны быть сильно связаны между собой, иначе его стоит разделить на несколько модулей. Различные модули должны быть связаны как можно меньше.

Идеальным является случай, когда связи между модулями совсем не образуют циклов: B не зависит от A (прямо или косвенно, через другие модули), если A зависит от B.

То же самое можно выразить в терминах горизонтальных и вертикальных зависимостей [16]. Пусть по вертикали идут уровни абстракции, а по горизонтали на каждом уровне – модули, соответствующие этому уровню. Так вот горизонтальных связей должно быть как можно меньше (лучше, чтобы не было совсем), в то время как вертикальные связи (следствие композиции) должны быть четкими.

Выполнение этого правила облегчает композицию и поддерживает систему в виде стройного набора модулей.