两个不同的Interface实现中的重复代码

时间:2019-02-10 19:00:58

标签: java duplicates code-duplication

对于每个实体,我都将创建一个控制器,一个服务和一个DAO。我现在有大约8个实体与这些课程。例如,以我的课程CategorieProduct为例。

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 个答案:

答案 0 :(得分:5)

您可以使用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允许对这些确切问题进行多重继承:您可以为每个CRUD操作定义类,并将它们用作Dao实现中的混合。接口中的默认方法非常接近多继承,但有一些限制,例如所有方法都必须为public,并且无法定义属性,而多重继承则不会出现。


对您的代码稍作评论:您可能会出现NullPointerException

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

在不知道closeSession(...)的确切实现的情况下,如果您不执行nullcheck,那么可能会抛出NPE,这不足为奇。如果SessionAutoCloseable,则可以使用try-with-resources。如果不是,则可以使用Optional来发挥自己的优势:

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

答案 1 :(得分:2)

最简单的解决方案是:

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()的实际签名!