Подтвердить что ты не робот

Геттеры и сеттеры, выполняющие дополнительную логику

У меня есть класс Java, который представляет собой корреляцию между двумя элементами (типичный POJO):

public class Correlation {

    private final String a;
    private final String b;

    private double correlation;

    public Correlation(String a, String b) {
        this.a = a;
        this.b = b;
    }

    public double getCorrelation() {
        return correlation;
    }

    public void setCorrelation(double correlation) {
        this.correlation = correlation;
    }

}

Чтобы следовать правильной логике корреляции, если a равно b, тогда значение корреляции должно быть ВСЕГДА 1. Я мог бы добавить логику, изменяющую метод getter (игнорировать факт возможного нулевого значения для a):

public double getCorrelation() {
    if (a.equals(b)) {
        return 1D;
    } else {
        return correlation;
    }
}

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

4b9b3361

Ответ 1

В ранние дни пары Java getter/setter использовались для идентификации свойств beans именно с целью дать возможность определить концептуальные атрибуты, реализованные посредством вычисления, а не просто переменную-член.

К сожалению, с течением времени программисты стали все больше полагаться на getter/setters, которые были просто аксессуарами/мутаторами для базовых атрибутов, тренда, которая была вроде сделана официальной с введением термина POJO для идентификации объектов, которые имели только геттеры и, возможно, сеттеры как методы.

С другой стороны, хорошо отличать объекты, которые выполняют вычисления от объектов, которые просто переносят данные; Я думаю, вы должны решить, какой тип класса вы хотите реализовать. На вашем месте я, вероятно, сделаю корреляцию дополнительным аргументом конструктора и проверю его достоверность там, а не на вашем получателе. Ваш Correlation не может быть вычислительным объектом, так как он не имеет достаточной информации для выполнения каких-либо вычислений.

Ответ 2

Побочные эффекты в геттерах и сеттерах обычно не отличная идея, поскольку обычно это не ожидается и может привести к сложным ошибкам. Я бы предложил создать метод "коррелята()" или что-то еще, что в данном случае не является геттером.

Надеюсь, что это поможет.

Ответ 3

Имеет смысл использовать значение во время setCorrelation(...). Например,

public void setCorrelation(double correlation) {
  if (a.equals(b)) {
    if (Math.abs(correlation - 1D) > EPSILON) {
      throw new InconsistentException(...);
    }
    this.correlation = 1D;
  } else {
    this.correlation= correlation;
  }
}

Я также хотел бы сделать свойство корреляции равным нулю, где a null указывает, что корреляция еще не установлена.

Ответ 4

Учитывая, что корреляция является как-то/иногда "полученным" значением из a и b (т.е. она равна 1, если a равно b, но она может быть рассчитана каким-то оригинальным способом в зависимости от (a, b), хороший вариант может вычислить корреляцию в конструкторе и вызвать исключение IllegalArgumentException в пределах setCorrelation, если vaule нарушает внутреннюю логику объекта:

public class Correlation {

    private final String a;
    private final String b;

    private double correlation;

    public Correlation(String a, String b) {
        this.a = a;
        this.b = b;
        calculateCorrelation();
    }

    protected calculateCorrelation() { 
        // open to more complex correlation calculations depending on the input,
        // overriding by subclasses, etc.
        if (a.equals(b)) {
            this.correlation = 1D;
        } else {
            this.correlation = 0;
        }
    }

    public double getCorrelation() {
        return correlation;
    }

    public void setCorrelation(double correlation) throws IllegalArgumentException {
        if (a.equals(b) && correlation != 1D) {
            throw new IllegalArgumentException("Correlation must be 1 if a equals b");
        }

        this.correlation = correlation;
    }
}

Следуя этой схеме, вы также можете "генерировать" свой класс корреляции.

Ответ 5

Я бы сказал что-то вроде getValue()

Ответ 6

Если бы я использовал ваш класс, я бы ожидал, что getCorrelation() вернет корреляцию. Фактически, я бы, вероятно, перепроектировал класс, чтобы иметь статический метод корреляцийElements (String a, String b), который возвращает double.

Ответ 7

В случаях, когда a!= b, как вычисляется корреляция?

Если корреляция вычисляется в основном из a и b, setCorrelation() следует удалить. Период. Корреляция должна рассчитываться в конструкторе или в методе getCorrelation(). Один принцип ООП заключается в группировке связанных данных и логики, поэтому расчет корреляции в идеале должен выполняться в классе, который вы ловко назвали Correlation. Если вычисление чрезвычайно сложно, оно может быть в другом месте (например, DIP), но вызов должен быть сделан из Correlation.

Если корреляция не вычисляется из a и b, я действительно не понимаю класс, поэтому "это зависит". Если a равно b, а кто-то вызывает setCorrelation (0.0), заключен контракт, чтобы спокойно игнорировать вызов и оставить корреляцию в 1.0 или выбросить исключение? И, если я пишу код вызова, я в затруднительном положении, так как не знаю, что произойдет, если я попытаюсь установить Корреляцию (0.0), потому что я понятия не имею, что такое a и b, или все, сделать звонок, я вынужден пойти if (getA().equals(getB())) и т.д. или поймать Исключение и сделать, э-э, что??? Что нарушает DRY, и именно поэтому ООП говорит, что логика и данные должны быть сгруппированы вместе в классе.