Геттеры и сеттеры, выполняющие дополнительную логику
У меня есть класс 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;
}
}
Что меня беспокоит, добавление этой логики к методу геттера, следует ли мне изменить имя метода или документацию, его следует считать достаточным?
Ответы
Ответ 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, и именно поэтому ООП говорит, что логика и данные должны быть сгруппированы вместе в классе.