Сохранение промежуточных результатов во время переопределения метода equals

Фактический случай:
я хотел бы переопределить public boolean equals(java.lang.Object obj) для некоторых объектов в моем текущем проекте Java. Этот метод по-прежнему должен возвращать true, когда объект вызова считается равным текущему. Однако при установлении равенства между объектами мне необходимо сохранить некоторые результаты обработки в структуре данных, принадлежащей другому, синглтону, классу (я должен сохранить список различий, если они есть, для дальнейшего использования в рабочем процессе приложения).

Вызов переопределенного equals() будет иметь побочный эффект, тесно связанный с тем, как я устанавливаю равенство объектов. Однако у метода нет побочных эффектов, если он не переопределен. Это считается недостатком конструкции? Есть ли хорошая практика, противоречащая такому подходу?

Документация Oracle о переопределении методов довольно лаконична, имхо, по этому поводу: «Способность подкласса переопределять метод позволяет классу наследоваться от суперкласса, поведение которого «достаточно близко», а затем модифицировать поведение по мере необходимости.».

Я не вижу никаких ограничений в таком заявлении, но я хотел бы получить совет от разработчиков/дизайнеров/архитекторов ООП.

Спасибо!

Подробнее (упрощенный код):

// Dataform is a JAX bean class
public class Dataform {
    String name;
    // Column is a JAX bean class
    ArrayList<Column> columns;
    // Footer is a JAX bean class
    Footer footer;

    // equals is redefined the same way for each JAX bean classes
    @Override
    public boolean equals(Object obj){
        if(this.getClass().isInstance( obj )){
            // equalsXML is a method that compares XML elements (JAX beans in this case). This method can in turn call equals() on 
            if (XMLObject.equalsXML( this, obj ).isEmpty()){
                // Store differences in singleton class for future access
                return false;
            }
            else{
                return true;
            }
        }
        else{
            return super.equals( obj );
        }
    }
}

person A. Karali    schedule 23.02.2016    source источник
comment
Не могли бы вы дать более подробное описание (например, код) о необходимости хранения некоторых результатов обработки.   -  person OneCricketeer    schedule 24.02.2016
comment
Кэширование обычно не считается побочным эффектом, это просто повышение производительности, позволяющее быстрее запрашивать кешированный результат при последующих использованиях, будь то из equals() или из другого места.   -  person Andreas    schedule 24.02.2016
comment
Если equals последовательно возвращает результат при вызове, и вы не изменяете сравниваемые объекты, побочных эффектов нет.   -  person OneCricketeer    schedule 24.02.2016
comment
Я только что отредактировал пост, мне действительно нужно сохранить обнаруженные при сравнении различия, если они есть.   -  person A. Karali    schedule 24.02.2016
comment
Я бы очень советовал вам этого не делать. Метод .equals() и бизнес-логика хранения и обработки этих различий так далеки друг от друга... Вы уверены, что вам действительно нужно делать это при каждом вызове .equals()? Вы уверены, что кто-то из ваших коллег (или вы сами) не будет использовать .equals() в каком-то месте, где вам не нужно обрабатывать эти различия, а потом не будет тратить часы на отладку, пытаясь понять, что пошло не так в продакшене? . Либо храните разницу явно в тех местах, где вы хотите это сделать, либо будьте рискованным парнем и используйте АОП.   -  person Yaroslav Admin    schedule 24.02.2016
comment
Или хотя бы напишите собственный метод для сравнения с побочным эффектом сохранения разницы. Просто как акт вежливости по отношению к будущим сопровождающим.   -  person Yaroslav Admin    schedule 24.02.2016
comment
Спасибо Ярослав. Метод equals() для этих компонентов JAX будет вызываться только один раз с определенным аргументом, как это предусмотрено в рабочем процессе приложения. После этого информация о равенстве сохраняется в структуре данных, доступной для всего приложения без необходимости повторной проверки объектов (база, вызов). Оценка того, равны ли два объекта Dataform, является дорогостоящим, я хотел сохранить эту информацию (а также различия, если они есть) только один раз. Я также добавлю защиту, которая предотвратит повторную обработку, если структура данных для текущего объекта уже была обновлена.   -  person A. Karali    schedule 24.02.2016
comment
@ A.Karali О, если это только кеширование, то я согласен с Андреасом. Это нормально. Но если за этим стоит какая-то бизнес-логика, то это плохая идея.   -  person Yaroslav Admin    schedule 24.02.2016
comment
Весь ваш equals метод просто return getClass().isInstance(obj)? !XMLObject.equalsXML(this, obj).isEmpty(): super.equals(obj);   -  person Holger    schedule 19.10.2016


Ответы (1)


Если вам нужно выполнить дополнительную обработку для конкретных методов (или почти чего угодно), не затрагивая код программы, рассмотрите аспектно-ориентированное программирование. Это метод изменения байт-кода либо во время компиляции, либо динамически. Звучит сложно, но это не так. Этот метод идеально подходит для ведения журнала, мониторинга, дополнительной безопасности, обработки исключений и многого другого. Лично я предпочитаю использовать его для вещей, не связанных с моделью предметной области. Представьте, что вам нужно вести журнал для всей программы. Вам нужно будет добавить дополнительную строку для каждого метода, который вы хотите зарегистрировать. С АОП вы можете сделать это всего несколькими строками, вообще не касаясь кода вашей программы. Прочтите об AspectJ. Это самый старый и, вероятно, самый продвинутый инструмент на данный момент (за исключением BCEL — фреймворка для прямого манипулирования байт-кодом).

person callOfCode    schedule 23.02.2016
comment
Спасибо, Юстас, я знаю об АОП, но здесь это не подходит для конкретного случая. Мне нужно хранить список различий (если они есть) между двумя объектами в определенной структуре данных, доступной из любой точки проекта (приложения). - person A. Karali; 24.02.2016
comment
@A.Karali Мне было бы интересно узнать больше о вашем коде. Являются ли данные, которые вы хотите сохранить, неизменяемыми? Если да, вы можете использовать фабрику, которая создает объекты и обрабатывает эти данные для вас. Вы можете реализовать интерфейсы для этих классов и использовать шаблон Decorator для тех, которые вам нужны. Или просто выполните эту обработку в переопределенных методах, если вы не хотите переусложнять свой код. Это не такая уж плохая идея, если вы не нарушаете SOLID. - person callOfCode; 24.02.2016
comment
Данные изменяемы, поскольку необходимо решить, что делать с сохраненными различиями (флаг в классе XMLDifference): применить различие к другой форме данных или игнорировать его. Я решил пойти на такую ​​обработку хранения различий в переопределенных равных, и в этом смысл вопроса, может ли это повредить хорошей практике? До сих пор, судя по предыдущим комментариям, так не кажется. - person A. Karali; 24.02.2016