具有CRUD静态方法的观察者模式和DAO类

时间:2015-04-23 16:05:55

标签: java dao observer-pattern

我正在审查一些DAO类,它们将CRUD静态方法create(),delete()等暴露给程序,并且每个DAO类通过Notification检查数据库中的更改来实现Observer模式。 java类,如果通过从数据库中提取对象而收到一个更改通知。

简化代码与此类似:

OfficeDAO.java

public class OfficeDAO implements PropertyChangeListener
{
    public OfficeDAO()
    {
        /* 
         * Below we add ourselves to the observers of class Notifications
         * (see observer pattern in Java) in practice we are notified
         * when one of our objects is changed by a remote client user
         */
        Notification.addChangeListener(this);
    }

    public static void create(Office office)
    {
      Connection connection = DBConnection.getConnection();

      //... stuff with the database insertion

      Notification.notifyDatabaseChanges("ocreate-" + officeId);
    }
}

现在的问题是addChangeListener(this);在构造函数中,但因为这个DAO类是通过其静态方法使用的,所以从不调用构造函数。

要在应用程序的main()方法中解决此问题(顺便说一下,在EDT线程内),可以调用:

new OfficeDAO(); //ignore this, it is needed only to start the DAO constructor

这看起来相当hacky所以我想添加一个

static {
  Notification.addChangeListener(this);
}
在OfficeDAO.java类中的

,但当然静态初始化程序中没有“this”引用,所以我没有解决方案。 从DAO方法中删除静态是没有问题的,因为这些方法在整个应用程序中被调用,并且在没有类的实例的情况下被调用。

我目前缺少任何干净的解决方案或解决方法吗?

3 个答案:

答案 0 :(得分:2)

这似乎是一个相当混乱的场景,创建一个新对象只是为了向Notification添加一个监听器似乎更像是一个反模式。我的假设是,这是一些遗留代码的一部分,并且可能没有太多的代码重新分解。我可以说,由于DAO层的作用更像是单例,您可以嵌入预先创建的DAO实例并通过静态引用访问它。

private static OfficeDAO myDAO = new OfficeDAO(); //The constructor code remains the same

答案 1 :(得分:0)

您可以将所有DAO类更改为Singleton。我同意不需要创建DAO实例,因为您的DAO没有状态,这不是一个理想的解决方案。但同样,您并不是在寻找一个理想的解决方案,而是在客户端代码中需要进行最少的更改。我不确定您是否在项目中使用IoC框架,但如果您决定在将来使用IoC框架,将DAO转换为Singleton将为此设置基础。

让我们将OfficeDAO转换为Singleton:

public class OfficeDAO implements PropertyChangeListener {

    private static volatile OfficeDAO INSTANCE;

    private OfficeDAO() {
        if (INSTANCE != null) {// prevent reflection attacks
            throw new InstantiationError("Illegal attempt to create more than one instance of OfficeDAO");
        }
        Notification.addChangeListener(this);
    }

    public static OfficeDAO getInstance() {
        OfficeDAO localInstance = INSTANCE;
        if (INSTANCE == null) {
            synchronized (OfficeDAO.class) {
                localInstance = INSTANCE;
                if (localInstance== null) {
                    INSTANCE = localInstance = new OfficeDAO();
                }
            }
        }
        return localInstance;
    }

    public void create(Office office) {
        Connection connection = DBConnection.getConnection();

        // ... stuff with the database insertion

        Notification.notifyDatabaseChanges("ocreate-" + officeId);
    }
}

如果您以类似方式更改所有DAO,则必须在客户端代码中进行的唯一更改是将ClassName.staticMethod()更改为ClassName.getInstance().staticMethod()

示例:OfficeDAO.getInstance().create(..)

* 话虽如此,它看起来你的Observers也是主题,这不是Observer模式实现的经典方式。此外,您可以避免双重检查锁定并使用不是懒惰实例化的单例。如何实施Singleton是您自己选择的问题,与问题没有直接关系。

如果您的项目开始使用Ioc框架(如Spring或Guice),则可以删除私有构造函数和getInstance方法。那么你最好的办法是将DAO中的所有静态方法更改为实例方法,并让IoC框架创建并将DAO注入所有需要它们的类中。这有几个好处:

  1. 大多数IoC框架允许您决定在请求时是否必须提供类的一个对象,或者每次请求时都应提供新对象。因此,您可以在Singleton与非Singleton DAO之间进行选择,而无需更改DAO。
  2. 您的数据源可能会从数据库更改为.csv文件,您无需更改使用DAO的客户端代码。
  3. 您实际上可以在服务类中模拟您的DAO以进行单元测试。

答案 2 :(得分:0)

DAO设计是一个非常复杂的主题,您可以在DAO design上阅读Balusc(此论坛上的用户)的文章,最后选择一个处理DAO和连接管理的框架。

一个非常纤薄的库,为您提供正确的DAO实现的良好开端是Butterfly Persistence,它将为您创建DAOFactory并管理连接,而无需导入100MB的Spring或Hibernate jar库。

至于为数据库操作添加监听器和通知程序,您应该完全避免这种情况,而是使用支持事件通知的数据库,例如Oracle或Firebird。

这样您只会侦听事件,数据库会通知您对其表的任何更改。