Просматривая код, который я написал, я наткнулся на следующую конструкцию, которая заставила меня задуматься. На первый взгляд кажется достаточно чистым. Да, в реальном коде getLocation()
метод имеет немного более конкретное имя, которое лучше описывает, в каком именно месте он находится.
service.setLocation(this.configuration.getLocation().toString());
В этом случае service
это переменная экземпляра известного типа, объявленная в методе. this.configuration
происходит от передачи в конструктор класса и является экземпляром класса, реализующего определенный интерфейс (который требует публичного getLocation()
метода). Следовательно, возвращаемый тип выражения this.configuration.getLocation()
известен; конкретно в этом случае это a java.net.URL
, тогда как service.setLocation()
хочет a String
. Поскольку два типа String и URL не совместимы напрямую, требуется какое- то преобразование, чтобы поместить квадратный колышек в круглое отверстие.
Однако , в соответствии с Законом о Деметре , как цитируется в чистом кодексе , метод F в классе C должен вызывать только методы на C , объекты , созданные или передаются в качестве аргументов е , и объекты проведены в переменных экземпляра C . Все, что выходит за рамки этого (последнее toString()
в моем конкретном случае выше, если только вы не рассматриваете временный объект, созданный в результате самого вызова метода, и в этом случае весь Закон кажется спорным) не допускается.
Существуют ли веские причины, по которым вызов, подобный указанному выше, с учетом перечисленных ограничений, должен быть запрещен или даже запрещен? Или я просто слишком придирчив?
Если бы я реализовать метод , URLToString()
который просто вызывает toString()
на URL
объект (например, возвращаемую getLocation()
) , переданного ей в качестве параметра, и возвращает результат, я мог бы обернуть getLocation()
вызов в ней для достижения точно такой же результат; по сути, я бы просто переместил конверсию на один шаг наружу. Это как-то сделает это приемлемым? (Мне кажется , интуитивно, что в любом случае это не должно иметь никакого значения, поскольку все, что нужно, - это немного изменить положение вещей. Однако, следуя приведенной выше букве закона Деметры, это было бы приемлемо, поскольку я будет работать непосредственно с параметром функции.)
Будет ли какая-то разница, если это будет что-то более экзотическое, чем вызов toString()
стандартного типа?
При ответе имейте в виду, что изменение поведения или API типа, к которому относится service
переменная, нецелесообразно. Также, ради аргумента, допустим, что изменение типа возвращаемого значения getLocation()
также нецелесообразно.
Закон Деметры - это руководство к дизайну, а не закон, которому нужно неукоснительно следовать.
Если вы чувствуете, что ваши классы достаточно разделены, то в этой строке нет ничего плохого,
this.configuration.getLocation()
особенно если, как вы говорите, нецелесообразно изменять другие части API.Я уверен, что клиент будет совершенно счастлив, даже если вы разложите Закон Деметры на куски, если вы будете доставлять то, что он хочет, и вовремя. Это не оправдание для создания плохого программного обеспечения, но напоминание о прагматичности при разработке программного обеспечения.
источник
this.configuration
это переменная экземпляра типа известного интерфейса, вызов метода для него, определенного этим интерфейсом, кажется вполне приемлемым даже в соответствии со строгой интерпретацией. Да, я знаю, что это руководство, как KISS, SOLID, YAGNI и так далее. В общем, очень мало, если вообще есть, «законов» (в юридическом смысле) в разработке программного обеспечения.Единственное, что я могу думать о том, чтобы не писать код, подобный этому, это что
this.configuration.getLocation()
делать, если возвращает ноль? Это зависит от вашего окружающего кода и целевой аудитории, использующей этот код. Но, как говорит Марко - закон Деметры - это правило большого пальца - хорошо следовать, но не ломайте себе спину, делая это без необходимости.источник
this.configuration.getLocation()
бы он возвратил ноль, то мы либо (а), скорее всего, никогда бы не зашли так далеко, либо (б) что-то катастрофическое произошло в промежуточный период, и в этом случае я бы хотел, чтобы код не работал. Так что, хотя это определенно верный пункт в целом, в этом конкретном случае можно с уверенностью сказать, что он не применим. Кроме того, все это и многое другое - это обработчик исключений, специально предназначенный для устранения непредвиденных ошибок.Строгое следование закону Деметры означало бы, что вы должны реализовать метод в объекте конфигурации, например:
но лично я не стал бы беспокоиться, потому что это такая маленькая ситуация, и в любом случае ваши руки как бы связаны из-за API, который вы не можете изменить. Правила программирования - это то, что вы должны делать, когда у вас есть выбор, но иногда у вас нет выбора.
источник