我正在审查一些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方法中删除静态是没有问题的,因为这些方法在整个应用程序中被调用,并且在没有类的实例的情况下被调用。
我目前缺少任何干净的解决方案或解决方法吗?
答案 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注入所有需要它们的类中。这有几个好处:
答案 2 :(得分:0)
DAO设计是一个非常复杂的主题,您可以在DAO design上阅读Balusc(此论坛上的用户)的文章,最后选择一个处理DAO和连接管理的框架。
一个非常纤薄的库,为您提供正确的DAO实现的良好开端是Butterfly Persistence,它将为您创建DAOFactory并管理连接,而无需导入100MB的Spring或Hibernate jar库。
至于为数据库操作添加监听器和通知程序,您应该完全避免这种情况,而是使用支持事件通知的数据库,例如Oracle或Firebird。
这样您只会侦听事件,数据库会通知您对其表的任何更改。