【问题标题】:Duplicate code inside two different Interface implementations两个不同接口实现中的重复代码
【发布时间】:2019-02-10 19:00:57
【问题描述】:

对于每个实体,我都在制作控制器、服务和 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 方法:get、insert、update、delete。大多数情况下,只是参数不同。

【问题讨论】:

  • 通常有两种方法: 将公共代码放入一个公共基类中,您的类从该基类扩展。或者将通用代码放入另一个类并在您的类中使用该类的实例。尝试使用第二种方法(优先组合而不是继承)。除此之外:过于宽泛和/或基于意见。

标签: java duplicates code-duplication


【解决方案1】:

你可以通过一个AbstractInsertable<T>-class 来解决这个问题,其中有一些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&lt;T&gt; 继承,例如CategorieDaoImpl extends AbstractInsertable&lt;Category&gt;。当然,这仅适用于仅从一个类继承的情况。

另一种选择是使用接口和默认实现。

答案到此结束。其余的都是我个人的意见。


我个人希望 Java 允许针对这些确切问题进行多重继承:可以为每个 CRUD 操作定义一个类,并将它们用作 Dao 实现中的混合。接口中的默认方法非常接近多继承,但有一些限制,例如所有方法都必须是public,并且不能定义属性,这不会出现在多重继承中。


对您的代码的一个小评论:您有可能出现NullPointerException

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

在不知道closeSession(...) 的确切实现的情况下,如果您没有执行空检查,我不会感到惊讶,因此可能会抛出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);
        }

【讨论】:

  • 非常感谢您的回答。我现在正在尝试实现它,看看它是如何工作的。再次感谢!
  • @ProxiHenn 我刚刚注意到您的代码中有一些内容。我更新了我的答案(最后一部分)。也许你想看看。
  • 我正在对 closeSession() 中的会话进行空检查
【解决方案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);
    }
}

当然,更“通用的答案”可能是您使用一些&lt;T extends some BaseType&gt; 类型参数而不是Object

如果没有这样的基类,那么下一个最好的办法是确定一个公共基接口或您打算保存的所有对象都可以/应该/需要实现的东西。

换句话说:你的选项空间很大程度上取决于session.save()的实际签名!

【讨论】:

  • @Andreas 哪个覆盖?谢谢,已修复。
猜你喜欢
  • 2014-03-05
  • 2021-08-05
  • 2011-09-04
  • 1970-01-01
  • 2017-02-19
  • 1970-01-01
  • 2018-02-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多