Закон Деметры: Доступ к статическому имуществу

У меня есть строка кода, выглядящая так:

String someString = "something"; if (Foo.SOME_CONSTANT_STRING.equals(someString))

что приводит к нарушению: «Потенциальное нарушение Закона Деметры (доступ к статическому свойству)»

Какой здесь предлагается подход?

(Правка: я изменил пример кода)


person Alix    schedule 09.10.2015    source источник
comment
Закон Деметры довольно суров. Следование этому по книге не всегда сделает вашу жизнь проще. Просто говорю.   -  person Sean Patrick Floyd    schedule 12.10.2015
comment
@ Шон Я заметил :-) Но я упрямый ... Я ударюсь головой еще несколько раз, прежде чем сдаться.   -  person Alix    schedule 13.10.2015


Ответы (4)


Вы должны написать

if ("hello".equals(Foo.SOME_CONSTANT_STRING))

потому что, насколько может знать PMD, Hello точно не null, тогда как Foo.SOME_CONSTANT_STRING может и не быть.

Кроме того, посетите страницу Википедии, посвященную Закону Деметры, чтобы лучше понять его.

person Seb - SonarSource Team    schedule 12.10.2015
comment
Мой пример был немного упрощен. привет была строковая переменная я думаю - person Alix; 12.10.2015
comment
Как PMD может думать, что Foo.SOME_CONSTANT_STRING может быть null, когда это final и установлено значение? Я благодарю вас за ссылку, но я не становлюсь мудрее, когда речь идет о конкретном случае доступа к статическим свойствам. Единственное предположение, которое у меня есть на данный момент, это то, что если бы Foo был вызывающим классом, я бы не получил это нарушение. - person Alix; 13.10.2015
comment
знание того, что Foo.SOME_CONSTANT_STRING не является константой null, требует ее разрешения. Чего Findbugs может не делать, если его нет в текущем классе. Глядя на ваш вопрос, я даже сам не могу этого сказать. Я могу предположить это, потому что это верхний регистр и Foo кажется классом, но я не могу этого знать. - person Seb - SonarSource Team; 13.10.2015
comment
Допустим, вы правы. Как я должен сравнить эти две строки (одну константу и одну строковую переменную) таким образом, чтобы не вызвать нарушений? Я не хочу перемещать константу в вызывающий класс Foo, так как на самом деле ей там не место, но, похоже, это единственный способ. - person Alix; 18.10.2015
comment
Вы хотите сказать, что переменная должна быть первой в сравнении? - person Alix; 19.10.2015
comment
Да, но "hello" на самом деле не является переменной. Это настоящая константа с точки зрения языка. - person Seb - SonarSource Team; 19.10.2015
comment
Контекст и детали очень важны, поэтому я изучил свой код, чтобы на этот раз получить как можно более точный пример (без упрощения): private boolean isXCharacteristic(BluetoothGattCharacteristic characteristic) { return BleUuid.X_CHARACTERISTIC.equals(characteristic.getUuid()); } Если я поменяю местами два сравниваемых объекта, я вместо этого получу цепочку методов, вызывающую нарушение LOD. - person Alix; 19.10.2015
comment
Как насчет: private boolean isXCharacteristic(BluetoothGattCharacteristic characteristic) { return BleUuid.isX_CHARACTERISTIC(characteristic.getUuid()); }? Это означает создание статического метода, который вызывает equal за кулисами и вообще не обращается к свойству... - person adangel; 19.11.2015

Проблема с доступом к статическим переменным заключается в том, что вы применяете к классу внешнее состояние, которое трудно протестировать. Вы должны получить к нему доступ через переменную класса, например:

private final Foo SOME_CONSTANT = Foo.SOME_CONSTANT_STRING;
public void doSomething(){
    String someString = "something";
    if (SOME_CONSTANT.equals(someString)){
        doTheWave();
    }
}

это, с геттером для SOME_CONSTANT, позволяет более точно проверить «начальное состояние» функции.

person bunyaCloven    schedule 02.11.2016
comment
Это будет полезно только для целей тестирования или имеет какое-либо другое преимущество. Так как мы должны снова объявить уже объявленные константы, написав дополнительный код. - person Gaurav Parek; 02.02.2018

@Аликс

Этот вопрос был довольно старым, и есть много ответов, но я думаю, что правильный ответ отсутствовал, поэтому я опускаю свой ответ:

SOME_CONSTANT_STRING должно быть объявлено final

Кроме того, как упоминалось ранее другими пользователями, вызов String.equals для объекта null String может привести к NPE (исключение нулевого указателя), и таких ситуаций лучше избегать в приложениях, чтобы не было непредсказуемого поведения. Аргумент null для String.equals вполне приемлем. Следовательно, если мы хотим использовать String константы (объекты) для выполнения таких сравнений, мы должны сделать эти константы final.

person deepak    schedule 11.07.2017

Честно говоря, я думаю, что статическое свойство в другом классе следует рассматривать как глобальную константу, которая доступна и разрешена Законом Деметры. Я не понимаю, почему она всегда должна определяться как переменная класса, кроме как для того, чтобы обойти реализацию правила в PMD и, возможно, чтобы избежать дублирования методов доступа с двойной или тройной точкой повсюду в классе. В некоторых случаях статический импорт может смягчить это.

https://github.com/pmd/pmd/issues/2179

Я поднял вышеуказанный вопрос для того же.

person fernal73    schedule 22.12.2019