Определить изменение значения объекта, переданного в качестве параметра - PullRequest
3 голосов
/ 13 февраля 2009

Я сейчас работаю с кодом, похожим на этот

public String getName(User user) {
     user.setSth(...);
     return user.getName();
}

Я считаю плохой практикой изменять объекты, передаваемые в качестве параметров. Есть ли инструмент, который обнаруживает такой код? Я посмотрел на findbugs, pmd и checkstyle, но не смог найти никакой проверки для этого.

P.S. извините за плохой пример.

Ответы [ 7 ]

2 голосов
/ 13 февраля 2009

Вы можете сделать User неизменным (объявите его final, объявите все свойства final и удалите сеттеры. Я знаю, что это невозможно везде, но во многих местах это хорошо, и у вас не будет проблем в передавая это другим функциям).

Если вам нужно что-то «изменить», вы можете реализовать такие функции, как newId в этом примере:

public final class User {
    private final String name;
    private final int id;

    User(String name, int id) {
        this.name = name;
        this.id = id;
    }

    public User newId(int newId) {
        return new User(this.name, newId);
    }

    //getters here;
}

Встроенные классы String, Integer, ... тоже делают это.

2 голосов
/ 13 февраля 2009

Я думаю, вы уже на правильном пути: ваш лучший инструмент для обнаружения такого рода кода почти наверняка Findbugs . Однако вам, вероятно, потребуется написать собственный детектор для этого шаблона. Вот пример того, как вы бы написали детектор, хотя это не совсем тот детектор, который вы ищете.

Предостережение : Я не совсем согласен, что побочный эффект всегда плохой стиль. Однако, если вы действительно хотите найти подобные вещи, я бы порекомендовал Findbugs.

2 голосов
/ 13 февраля 2009

Вы ничего не найдете, потому что, с точки зрения инструмента, «getName» и «setSth» - это просто вызовы метода. Люди говорят «это добытчик» и «это установщик», а инструменты - нет. Фактически, getName () не является геттером, потому что геттеры не принимают аргументы.

Так что инструмент не может видеть ничего необычного, потому что методы постоянно меняют объекты.

Если вы хотите применить это правило, взгляните на расширение findbugs и PMD. Оба позволяют вам определить дополнительные ограничения. Вероятно, вы ищете:

  • Если имя метода начинается с "get"
  • И тело метода вызывает метод любого объекта, передаваемого в качестве параметра

затем напечатайте предупреждение. Это не должно занять слишком много времени. Запустите это, и вы увидите, сколько «ложных срабатываний» вы получите (предупреждения о методах, которые на самом деле в порядке). Это поможет вам определить, стоит ли заниматься этим дальше. Кроме того, у вас будет новый элемент для добавления в ваше резюме:)

1 голос
/ 13 февраля 2009

На самом деле это то, что в C ++ было очень легко сделать с помощью квалификатора const. Вы определяете параметр как const, и для этого параметра вы можете вызывать только методы, определенные как const - обычно это геттеры.

В Java это отсутствует и, честно говоря, я не против. Как уже упоминалось, есть анализаторы исходного кода, которые могут проверить это поведение, а также методы метапрограммирования, чтобы сделать это.

Лично я считаю, что если метод имеет правильное имя, нет проблем с передачей ему объекта, так что он изменяется.

1 голос
/ 13 февраля 2009

Вы можете создать интерфейс под названием UserView, содержащий только «получатели», заставить пользователя реализовать его и использовать новый интерфейс UserView в качестве типа параметра.

interface UserView{
 public String getName();
...

class User implements UserView...

public String getName(UserView user) {
     user.setSth(...); // Will not compile
     return user.getName();
}
0 голосов
/ 13 февраля 2009

Вы ищете что-то вроде "const" в C ++, которое заставит сделать значение параметра таким же неизменным, как и переданная ссылка. Неизменяемые объекты гарантируют это, если вы можете жить с ними.

Вы утверждаете, что это "плохо", потому что подобные побочные эффекты могут удивить пользователя. Это действительно так, но вредно, только если это нежелательный сюрприз.

0 голосов
/ 13 февраля 2009

Существуют инструменты, которые могут «рассуждать» о коде на более высоком уровне, чем обычно делают компиляторы. Например, декларативное метапрограммирование - это дисциплина, которая позволяет написанию программ проверять, соответствует ли другая программа определенному дизайну, или, наоборот, моему для запахов кода и антишаблонов.

Некоторые ссылки:

http://prog.vub.ac.be/DMP/

http://www.cs.bris.ac.uk/Publications/pub_master.jsp?id=1000273

а для остальных

http://www.google.com/search?num=100&hl=en&q=Declarative+Metaprogramming

...