Здравствуйте, samius, Вы писали:
ARK>>А в чем в таком случае смысл закона? Мы все равно вызываем нужный нам метод, просто "per rectum".
S>Именно в этом и смысл, что "per rectum" можно, а намрямую — нет.
Ну, если рассматривать чисто эти 5 пунктов определения, то да, они допускают и такую трактовку.
Хотя там же написано: "If the law is followed, only object B knows its own internal structure".
Да и во всех других обсуждениях пишут аналогичное, например тут:
http://c2.com/cgi/wiki?LawOfDemeter
S>Но если вспомнить что метод Foo::Bar по сути есть статический метод, принимающий неявный параметр типа Foo, то мы получаем что foo.Bar() есть ни что иное как Foo::Bar(foo), и foo.Bar() лишь синтаксический сахар. Во всяком случае для некого подмножества языков. С виртуальными методами чуть сложнее, ну да фиг с ними пока.
Мало того, в таком случае получается, что мы можем вызывать любые цепочки методов — мы ведь просто вызываем статические методы класса в засахаренном виде. Определение становится бессмысленным. Значит в нем явно чего-то не хватает.
S>В итоге смысл закона сводится к тому что в контексте метода m FooBar(foo) лучше чем Foo::Bar(foo). И не совсем очевидно, чем это лучше с позиций знания внутреннего устройства класса Foo.
С этих позиций ничем не лучше. Просто странный способ укорачивания метода.
ARK>>(Аналогично можно и просто присвоить объект в локальную переменную, а потом дернуть метод у этой переменной.)
S>Нет, формально присвоение локальной переменной не разрешает дергать этот метод. А в глобальную — разрешает.
Ну что же, локальные переменные LoD вообще запрещает использовать?
Про них ничего не написано, да, но что-то с ними можно делать?
ARK>>Но по идее-то LoD, как я его понимаю, запрещает нам оперировать внутренней структурой объекта _в принципе_ (а не только в текущем методе).
S>Проблема в том, что именно формальные требования закона запрещает оперировать внутренней структурой объекта лишь в определенных случаях. И передача объекта в глобальную переменную или в сторонний метод фактически снимают это ограничение. Неформально мы можем искать и находить в законе любые смыслы, но формальное его определение сводит его к абсурду.
Ну, если уж подходить с позиций буквоедства, то в определении не сказано, что мы имеем право присваивать глобальные переменные и передавать объекты в другие методы (так же, как не сказано про поля объекта). Вызывать методы у глобальных переменных можем, да. А присваивать — вовсе не факт.
Так что формальное определение не то что сводит к абсурду, оно просто неполное и допускает разные трактовки.
S>Я не вижу в формальном описании ничего о поле текущего объекта
S>Правда, там есть пункт 4. o's direct component objects, но смысл этого пункта ускользает от меня в контексте этого закона. Если он о полях объекта o', то почему было не написать об этом прямо, как в пункте 5 о глобальных переменных?
Про это написал выше.
ARK>>Ну а если оператор таки метод объекта? Скажем, в Smalltalk или Eiffel.
S>в таком случае — да, нарушаем.
Тут можно конечно высосать из пальца "трактовку", что "2 + 3" равносильно созданию объекта в текущем методе. Правда, тогда то же самое можно сказать о любых значениях, которые были возвращены вызванными методами.
ARK>>Насчет статических объектов... Это по сути вырожденный случай обычных объектов, существующих в одном экземпляре. На мой взгляд, выделять их в отдельную касту не стоит.
S>Может и не стоит, но LoD ставит их как раз отдельной кастой. Раз статический объект не может быть "получен" и "передан", его методы можно вызывать без каких-либо ограничений, невзирая на соображения о знаниях на счет "внутреннего устройства" такого объекта.
Опять же, строго говоря, в определении про это ничего нет. Ни в один из 5 пунктов статические объекты не помещаются. Не факт, что мы должны их по умолчанию разрешить, может быть наоборот?
ARK>>Некий резон на самом деле имеется. В первом случае у нас контролируемое изменение объекта, о котором этот объект знает. Во втором мы лезем грязными руками внутрь и можем наломать дров. Видел жуткий говнокод (если конкретно, то во фреймворке MapXtreme), когда объект подписывался на изменения своих собственных полей на разных уровнях вложенности. Это мега-жесть.
S>Как раз LoD не запрещает такую мега-жесть. Со своими собственными методами все что угодно.
Не запрещает, но делает бессмысленным (в той трактовке, в какой я его понимаю). Т.к. извне уже нельзя разрушить структуру объекта, все изменения полей идут через его методы, так что городить лапшу из подписки уже не надо — достаточно проконтролировать несколько точек входа в самом объекте.
ARK>>А вот это уже что-то иное. Возможно, граница пролегает либо тут: "у вложенных объектов можно дергать только чистые функции", либо тут: "объект может выставлять наружу только примитивные value-типы, которые можно использовать любым способом".
S>Мне не кажется что тут. В тот момент, когда мы разрабатываем публичный интерфейс некого объекта, мы уже решаем, какие знания об объекте будут лишними для использования извне. Здесь мы руководствуемся минимальностью, полнотой, непротиворечивостью, стабильностью публичного интерфейса, принципами инкапсуляции (в широком смысле слова как дуализмом абстракции). Уже на этом этапе при удачном проектировании из объекта не должно торчать то, что сделает его клиентов зависимым от деталей реализации объекта.
S>А LoD как раз безотносителен соображений успешности проектирования интерфейса объекта (и частоты его использования) и относителен лишь того, каким образом был получен объект внутри метода (параметром ли, инстанциирован ли напрямую, взят ли из глобальной переменной, либо иным способом).
Вот я считаю как раз, что определение (расширенное) должно влиять именно на структуру создаваемого объекта. Как я уже упоминал, именно это подразумевается в литературе и виденных мной обсуждениях в инете.
S>Печально так же что прямое следование LoD ничего от нас не требует в отношении проектирования, т.к. исправление формального нарушения LoD тривиально без каких либо изменений в дизайне используемых компонент. Побочным эффектом появляется куча временных полей (которые могли бы быть локальными) и делегирующих методов.
Появление делегирующих методов в самом объекте местами неизбежно, да. И если их окажется слишком много, то это показатель того, что что-то не так.
А про временные поля в "Чистом коде" Мартина утверждается, что это хорошо — главное чтобы класс не был большим и не имел много обязанностей.