Дисциплины - Объектно-ориентированное программирование

ООП в Java - Программирование по контракту

Контракты - это своего рода соглашения программиста с определенным правилом написания кода. В Java имеются как встроенные контракты, такие как методы equals() и hasCode(), так и контракты библиотечных зависимостей, например COFOJA от Google.

Рассмотрим использование контракта equals().

Контракт equals() необходим в Java для подтверждения или отрицания того факта, что два объекта одного происхождения являются логически равными. То есть, сравнивая два объекта, программисту необходимо понять, эквивалентны ли их значимые поля. Не обязательно все поля должны быть идентичны, так как метод equals() подразумевает именно логическое равенство. Но иногда нет особой необходимости в использовании этого метода. Как говорится, самый легкий путь избежать проблем, используя тот или иной механизм — не использовать его. Также следует заметить, что однажды нарушив контракт equals вы теряете контроль над пониманием того, как другие объекты и структуры будут взаимодействовать с вашим объектом. И впоследствии найти причину ошибки будет весьма затруднительно.

Когда не стоит переопределять этот метод

  • Когда каждый экземпляр класса является уникальным.
  • В большей степени это касается тех классов, которые предоставляют определенное поведение, нежели предназначены для работы с данными. Таких, например, как класс Thread. Для них реализации метода equals, предоставляемого классом Object, более чем достаточно. Другой пример — классы перечислений (Enum).
  • Когда на самом деле от класса не требуется определять эквивалентность его экземпляров.
  • Например для класса java.util.Random вообще нет необходимости сравнивать между собой экземпляры класса, определяя, могут ли они вернуть одинаковую последовательность случайных чисел. Просто потому, что природа этого класса даже не подразумевает такое поведение.
  • Когда класс, который вы расширяете, уже имеет свою реализацию метода equals и поведение этой реализации вас устраивает.
  • Например, для классов Set, List, Map реализация equals находится в AbstractSet, AbstractList и AbstractMap соответственно.
  • И, наконец, нет необходимости перекрывать equals, когда область видимости вашего класса является private или package-private и вы уверены, что этот метод никогда не будет вызван.

При переопределении метода equals разработчик должен придерживаться основных правил, определенных в спецификации языка Java.

  • Рефлексивность
  • для любого заданного значения x, выражение x.equals(x) должно возвращать true.
    Заданного — имеется в виду такого, что x != null
  • Симметричность
  • для любых заданных значений x и y, x.equals(y) должно возвращать true только в том случае, когда y.equals(x) возвращает true.
  • Транзитивность
  • для любых заданных значений x, y и z, если x.equals(y) возвращает true и y.equals(z) возвращает true, x.equals(z) должно вернуть значение true.
  • Согласованность
  • для любых заданных значений x и y повторный вызов x.equals(y) будет возвращать значение предыдущего вызова этого метода при условии, что поля, используемые для сравнения этих двух объектов, не изменялись между вызовами.
  • Сравнение null
  • для любого заданного значения x вызов x.equals(null) должен возвращать false.

Нарушение контракта equals

Многие классы, например классы из Java Collections Framework, зависят от реализации метода equals(), поэтому не стоит им пренебрегать, т.к. нарушение контракта этого метода может привести к нерациональной работе приложения и в таком случае найти причину будет достаточно трудно. Согласно принципу рефлексивности, каждый объект должен быть эквивалентен самому себе. Если этот принцип будет нарушен, при добавлении объекта в коллекцию и при последующем поиске его с помощью метода contains() мы не сможем найти тот объект, который только что положили в коллекцию. Условие симметричности гласит, что два любых объекта должны быть равны независимо от того, в каком порядке они будут сравниваться. Например, имея класс, содержащий всего одно поле строкового типа, будет неправильно сравнивать в методе equals данное поле со строкой. Т.к. в случае обратного сравнения метод всегда вернет значение false.

// Нарушение симметричности
public class SomeStringify {
    private String s;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof SomeStringify) {
            return s.equals(((SomeStringify) o).s);
        }
        // нарушение симметричности, классы разного происхождения
        if (o instanceof String) {
            return s.equals(o);
        }
        return false;
    }
}
/Правильное определение метода equals
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    return o instanceof SomeStringify &&
            ((SomeStringify) o).s.equals(s);
}

Количество комментариев: 0

Для того, чтобы оставить коментарий необходимо зарегистрироваться
814301 БГУИР
814302 БГУИР
814303 БГУИР
894351 БГУИР
90421 БГУИР


Изображения Видео

1. Абстрактная фабрика https://www.youtube.com/watch?v=1mVONOCxfLg
2. Фабричный метод https://www.youtube.com/watch?v=5UqUDR6_2cY
3. Шаблон декоратор https://www.youtube.com/watch?v=Lwb9bm8yKD0
4. Dessign patterns on PHP https://github.com/domnikl/DesignPatternsPHP
5. Приёмы объектно-ориентированного проектирования. Паттерны проектирования Э. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссидес; [пер. с англ.: А. Слинкин науч. ред.: Н. Шалаев]. — Санкт-Петербург [и др.] : Питер, 2014. — 366 с. : ил. ; 24 см.
6. Приемы объектно-ориентированного проектирования. Паттерны проектирования Э. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссидес; [пер. с англ.: А. Слинкин науч. ред.: Н. Шалаев]. — Санкт-Петербург [и др.] : Питер, 2014. — 366 с. : ил. ; 24 см.
7. Ajax http://erud.by/ajax
8. Ajax http://erud.by/ajax
9. Ajax http://erud.by/ajax
10. Документация Laravel http://laravel.com
Задание к курсовой работе
Задание к курсовой работе
Вопросы к экзамену