Правильный способ реализации контракта равных

У меня есть объект домена под названием Пользователь. Свойства пользователя включают в себя ssoId, имя, адрес электронной почты, создал By, madeDate и userRole. Из них ssoId должен быть уникальным в том смысле, что два пользователя не могут иметь одинаковый идентификатор sso. Поэтому мой метод equals проверяет идентификатор sso и возвращает либо true, либо false.

@Override public boolean equals(Object o) {
    if (!(o instanceof User))
      return false;
    return user.getSsoId().equals((User)o.getSsoId());
}

Я чувствую, что это неправильная реализация, хотя она верна в отношении бизнес-правил. Вышеприведенная реализация вернет true для двух объектов с одинаковым идентификатором sso, но с разными значениями, скажем, name или email или обоих. Должен ли я изменить свой контракт на равенство, чтобы проверить равенство всех полей? Что вы предлагаете?

4 ответа

Решение

Это (почти) правильно для "технического равенства", но не для "естественного равенства". Чтобы достичь высшего технического равенства, вы также должны проверить рефлексив o == this, Может случиться так, что объект еще не сохранен в БД и, следовательно, еще не имеет технического идентификатора. Например

public class User {

    private Long id;

    @Override
    public boolean equals(Object object) {
        return (object instanceof User) && (id != null) 
             ? id.equals(((User) object).id) 
             : (object == this);
    }

    @Override
    public int hashCode() {
        return (id != null)
             ? (User.class.hashCode() + id.hashCode())
             : super.hashCode();
    }

}

Для "естественного равенства" лучше сравнить все нетехнические свойства. Для "сущностей реального мира" это, в конце концов, более надежно (но и дороже), чем техническое равенство.

public class User {

    private String name;
    private Date birth;
    private int housenumber;
    private long phonenumber;

    @Override
    public boolean equals(Object object) {
        // Basic checks.
        if (object == this) return true;
        if (!(object instanceof User)) return false;

        // Property checks.
        User other = (User) object;
        return Objects.equals(name, other.name)
            && Objects.equals(birth, other.birth)
            && (housenumber == other.housenumber)
            && (phonenumber == other.phonenumber);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, birth, housenumber, phonenumber);
    }

}

Правда, кода много, когда свойств много. Немного приличная IDE (Eclipse, Netbeans и т. Д.) Может просто генерироваться автоматически equals(), hashCode() (а также toString(), добытчики и сеттеры) для вас. Воспользуйтесь этим. В Eclipse щелкните правой кнопкой мыши код и загляните в пункт меню Source (Alt + Shift + S).

Смотрите также:

То, что вы делаете, кажется нормальным, и вы не нарушаете ни одно из правил, equals должен следовать.

Вы все еще можете проверить другие поля, чтобы не менять equalsсемантика, но для обнаружения несоответствия в вашей бизнес-логике, и, возможно, вызвать утверждение / исключение.

Это сложное решение.

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

Существуют различные виды равенства... есть равенство идентичности объекта, равенство данных объекта, равенство всего объекта... вы также можете включить туда информацию аудита.

Дело в том, что "равный" имеет много возможных значений.

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

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

Если в вашей модели ssoid должен быть уникальным, это означает, что значения для других полей не должны быть разными для двух экземпляров User. Если вы хотите проверить это предположение, вы можете сделать это с помощью утверждений в методе equals, если накладные расходы не являются проблемой.

Другие вопросы по тегам