Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, samius, Вы писали:
ARK>Ну вот, повод нашелся.
Угу
S>>Не совсем так. Это "что-то" можно передать параметром куда-нибудь (в свой метод, в метод объекта, инстанциированного в текущем методе, либо в метод глобального объекта). Запрещается лишь вызывать его метод.
ARK>А в чем в таком случае смысл закона? Мы все равно вызываем нужный нам метод, просто "per rectum".
Именно в этом и смысл, что "per rectum" можно, а намрямую — нет. Правда, тут еще требуется разобраться где проходит грань между "per rectum" и прямым подходом. Допустим
var foo = GetFoo();
foo.Bar(); // Нельзя, слишком прямо
FooBar(foo); // Можно, ибо Per rectum
Но если вспомнить что метод Foo::Bar по сути есть статический метод, принимающий неявный параметр типа Foo, то мы получаем что foo.Bar() есть ни что иное как Foo::Bar(foo), и foo.Bar() лишь синтаксический сахар. Во всяком случае для некого подмножества языков. С виртуальными методами чуть сложнее, ну да фиг с ними пока.
В итоге смысл закона сводится к тому что в контексте метода m FooBar(foo) лучше чем Foo::Bar(foo). И не совсем очевидно, чем это лучше с позиций знания внутреннего устройства класса Foo.
ARK>(Аналогично можно и просто присвоить объект в локальную переменную, а потом дернуть метод у этой переменной.)
Нет, формально присвоение локальной переменной не разрешает дергать этот метод. А в глобальную — разрешает.
ARK>Но по идее-то LoD, как я его понимаю, запрещает нам оперировать внутренней структурой объекта _в принципе_ (а не только в текущем методе).
Проблема в том, что именно формальные требования закона запрещает оперировать внутренней структурой объекта лишь в определенных случаях. И передача объекта в глобальную переменную или в сторонний метод фактически снимают это ограничение. Неформально мы можем искать и находить в законе любые смыслы, но формальное его определение сводит его к абсурду.
S>>Согласен. Тупо. Но формально (если мы используем конкретно эти формулировки) и не всякое поле подойдет. Глобальная переменная — подойдет. Поле объекта чей метод выполняется — нет. И это еще более тупо.
ARK>Почему же поле текущего объекта не подойдет? Вроде бы не видно в определении чего-то, противоречащего этому.
Я не вижу в формальном описании ничего о поле текущего объекта
Правда, там есть пункт 4. o's direct component objects, но смысл этого пункта ускользает от меня в контексте этого закона. Если он о полях объекта o', то почему было не написать об этом прямо, как в пункте 5 о глобальных переменных?
ARK>>>Еще непонятный момент с операторами. Например, в выражении "(a + b) / 3" оператор деления уже нарушает сабж.
S>>формально — нет. Дело в том, что оператор деления "/" обычно не метод объекта результата суммы a и b. Вообще, когда мы вызываем статический метод (а оператор деления "/" обычно можно считать именно таковым), закон Деметры неприменим.
ARK>Ну а если оператор таки метод объекта? Скажем, в Smalltalk или Eiffel.
в таком случае — да, нарушаем.
ARK>Насчет статических объектов... Это по сути вырожденный случай обычных объектов, существующих в одном экземпляре. На мой взгляд, выделять их в отдельную касту не стоит.
Может и не стоит, но LoD ставит их как раз отдельной кастой. Раз статический объект не может быть "получен" и "передан", его методы можно вызывать без каких-либо ограничений, невзирая на соображения о знаниях на счет "внутреннего устройства" такого объекта.
ARK>Некий резон на самом деле имеется. В первом случае у нас контролируемое изменение объекта, о котором этот объект знает. Во втором мы лезем грязными руками внутрь и можем наломать дров. Видел жуткий говнокод (если конкретно, то во фреймворке MapXtreme), когда объект подписывался на изменения своих собственных полей на разных уровнях вложенности. Это мега-жесть.
Как раз LoD не запрещает такую мега-жесть. Со своими собственными методами все что угодно.
S>>Особенно если это a.Name.Substring(...) или что-то вроде. Не делать же метод A.NameSubstring(...).
ARK>А вот это уже что-то иное. Возможно, граница пролегает либо тут: "у вложенных объектов можно дергать только чистые функции", либо тут: "объект может выставлять наружу только примитивные value-типы, которые можно использовать любым способом".
Мне не кажется что тут. В тот момент, когда мы разрабатываем публичный интерфейс некого объекта, мы уже решаем, какие знания об объекте будут лишними для использования извне. Здесь мы руководствуемся минимальностью, полнотой, непротиворечивостью, стабильностью публичного интерфейса, принципами инкапсуляции (в широком смысле слова как дуализмом абстракции). Уже на этом этапе при удачном проектировании из объекта не должно торчать то, что сделает его клиентов зависимым от деталей реализации объекта.
А LoD как раз безотносителен соображений успешности проектирования интерфейса объекта (и частоты его использования) и относителен лишь того, каким образом был получен объект внутри метода (параметром ли, инстанциирован ли напрямую, взят ли из глобальной переменной, либо иным способом).
Печально так же что прямое следование LoD ничего от нас не требует в отношении проектирования, т.к. исправление формального нарушения LoD тривиально без каких либо изменений в дизайне используемых компонент. Побочным эффектом появляется куча временных полей (которые могли бы быть локальными) и делегирующих методов.