Дублирующий код внутри двух разных реализаций интерфейса

Для каждого объекта я делаю контроллер, сервис и DAO. У меня сейчас около 8 сущностей с этими классами. Давайте возьмем, к примеру, мои занятия Categorie а также Product,

Учебный класс CategorieDaoImpl реализует методы из CategorieDao

@Override
public boolean insertCategorie(Categorie categorie) {
    Session session = null;
    try {
        session = super.getConnection();
        session.getTransaction().begin();
        session.save(categorie);
        session.getTransaction().commit();
        return true;
    } catch (HibernateException e) {
        e.printStackTrace();
        return false;
    } finally {
        closeConnection(session);
    }
}

Учебный класс ProductDaoImpl реализует методы из ProductDao

@Override
public boolean insertProduct(Product product) {
    Session session = null;
    try {
        session = super.getConnection();
        session.getTransaction().begin();
        session.save(product);
        session.getTransaction().commit();
        return true;
    } catch (HibernateException e) {
        e.printStackTrace();
        return false;
    }
    finally {
        closeConnection(session);
    }
}

Как видите, код двух классов довольно похож, кроме параметров и параметров save(),

Intellij говорит мне, что это дублирующий код, но не дает мне решения, как обычно, когда дублирующий код находится внутри класса. Любая идея, как я могу решить это и сделать это лучше?

Заранее спасибо.

РЕДАКТИРОВАТЬ:

Большинство классов Dao имеют одинаковые методы CRUS: получить, вставить, обновить, удалить. В основном, только параметр отличается.

2 ответа

Решение

Вы можете решить проблему с AbstractInsertable<T> -класс, который имеет некоторые public boolean insert(T t) держа ваш код:

public abstract class AbstractInsertable<T> extends ... {
    public boolean insert(T t) {
        Session session = null;
        try {
            session = super.getConnection();
            session.getTransaction().begin();
            session.save(t);
            session.getTransaction().commit();
            return true;
        } catch (HibernateException e) {
            e.printStackTrace();
            return false;
        } finally {
            closeConnection(session);
        }
    }

    [...]
}

Реализации могут наследовать от этого AbstractInsertable<T> например, CategorieDaoImpl extends AbstractInsertable<Category>, Это, конечно, работает только до тех пор, пока вы наследуете только от одного класса.

Другой альтернативой может быть работа с интерфейсами и реализациями по умолчанию.

Ответ заканчивается здесь. Остальное мое личное мнение.


Моим личным желанием было бы, чтобы Java разрешала множественное наследование для этих точных задач: вы можете определить classs для каждой CRUD-операции и использовать их в качестве миксинов в Dao -implementations. Методы по умолчанию в интерфейсах довольно близки к множественному наследованию, но имеют некоторые ограничения, например, все методы должны быть public и никакие атрибуты не могут быть определены, которые не будут присутствовать при множественном наследовании.


Незначительное замечание в вашем коде: у вас есть возможность NullPointerException происходить:

        Session session = null;
        try {
            session = super.getConnection();
            [...]
        } finally {
            closeSession(session);
        }

Не зная точной реализации closeSession(...) Я не удивлюсь, если вы не выполняете проверку на ноль, таким образом NPE может быть брошено. Если Session является AutoCloseable Вы могли бы использовать try-with-resources, Если это не так, вы можете использовать Optional в ваших интересах:

        Optional<Session> optionalSession = Optional.empty();
        try {
            optionalSession = Optional.of(super.getConnection());
            session = optionalSession.get();
            [...]
        } finally {
            optionalSession.ifPresent(this::closeSession);
        }

Самым простым решением будет:

public boolean insertGeneric(Object whatever) {
    Session session = null;
    try {
        session = super.getConnection();
        session.getTransaction().begin();
        session.save(whatever);
        session.getTransaction().commit();
        return true;
    } catch (HibernateException e) {
        e.printStackTrace();
        return false;
    } finally {
        closeConnection(session);
    }
}

Конечно, более "общий ответ" может быть то, что вы используете некоторые <T extends some BaseType> введите параметр вместо Object,

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

Другими словами: ваш выбор места в значительной степени зависит от фактической подписи session.save()!

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