Страницы

Поиск по вопросам

пятница, 1 февраля 2019 г.

Чистый код: Непонятный закон Деметры

Сейчас читаю книгу ЧИстый код на небольшой главе про закон Деметры. До этого с ним сталкивалась в паттернах от O'reilly (HeadFirst) и там было немного и понятно. После чистого кода - в голове кавардак. Есть пара вопросов:
1) Мартин делит объекты на объекты и структуры данных. Что тут подразумевается под структурой? Struct (в c# к примеру) или в целом объект класса в котором кроме открытых полей (или свойств) нету больше ничего (методов, например)?
2) Из первого вопроса вытекает непонимание того, что подразумевается под гибридом (наполовину объект, наполовина структура данных), который лучше не писать. Считается ли гибридом, например, объект класса "Машина", где можно и цвет ее посмотреть, и колеса даже поменять, и поведение у нее тоже есть?
3) Этот вопрос поднимала на устное обсуждение в другими разрабами (мы не джуны, но и не "крутыши") и также возникло непонимание самой сути этого закона, зачем его соблюдать, что является главной причиной: или база для дальнейших легковносимых изменений, или сокрытие внутренней структуры объекта, или даже легкое предотвращение и обработка NullReferenceException? Все понимают по разному.
4) Нарушается ли закон при разделении методов "плохих" на много маленьких?
Было
public class Class1 { public String DoSmth() { //Вроде как закон нарушен, потому что вызываем метод у вернувшегося значения return MethodClass1().DoSmth(); }
public Class2 MethodClass1() { return new Class2(); } }
public class Class2 { public String DoSmth() { String res2 = this.MethodClass2(); return res2; }
public String MethodClass2() { return "test"; } }
Стало
public class Class1 { public String DoSmth() { //теперь тут вызываются только методы того же класса Class2 res1 = MethodClass1(); return this.MethodClass1_2(res1); }
public Class2 MethodClass1() { return new Class2(); }
public String MethodClass1_2(Class2 val) { return val.DoSmth(); } }
Еще один маленький апдейт: лично у меня сложилось пока такое отношение: это какое-то правило, необходимость явного нарушения которого является индикатором того, что что-то не так спроектировано и можно найти решение, которое будет лучше и по бизнес-логике и по дальнейшему сопровождению.


Ответ

В книге "Программист-прагматик" (Хант, Томас) закон Деметера (такой кривой перевод) сведён к короткому высказыванию:
Минимизируйте связывание между модулями
Пример из книги на C++
class Demeter { private: A* a; int func(); public: void example(B& b); }
void Demeter::example(B& b) { int f = func(); // 1
b.invert(); // 2
a = new A(); a->setActive(); // 3
C c; c.print(); // 4 }
Закон Деметры для функций гласит, что любой метод некоторого объекта может обращаться только к методам принадлежащим:
самим себе любым параметрам, переданным в метод любым создаваемым им объектам любым непосредственно содержащимся объектам компонентов
Исходя из этого можно дать ответ на ваш вопрос №3: уменьшение связанности облегчает модификацию и сопровождение кода, облегчает написание тестов.
На практике это означает, что придётся создавать большое количество методов-оболочек, которые просто направляют запрос далее к делегату. Эти методы-оболочки влекут за собой расходы, ухудшая производительность и занимая память.
Обращая закон Деметры и плотно связывая несколько модулей, можно получить выигрыш в производительности.

Комментариев нет:

Отправить комментарий