昨天還在用Torque,今天聽說Hibernate更好,明天說不準又有更好的持久層工具...
如何使應用程序不變化的情況下選擇不同的持久層呢?
看看Finetix LLC的資深顧問Charles Chan 給我們現身說法。
Charles Chan
在文章 Object-Relational Mapping with Apache Jakarta OJB
中介紹了Apache OJB的使用,并在文章附錄中提到一種屏蔽不同持久層的設計思路,他采用了工廠方法模式(Factory Method),并通過實例Apache OJB來說明他的設計。
這個設計有兩個產品,一個是PersistenceManager,另一個是Transaction 。
OJBPersistenceManager和OJBTransaction 分別是兩個產品的實現。
It is often desirable to decouple your application from the specifics of a persistence framework, so that you can easily switch frameworks in the future. I recommend creating custom PersistenceManager and Transaction classes for this purpose. For example:
Example?
13
:?PersistenceManager?and?Transaction?Interfaces

/**?*/
/**
*?The?abstract?base?class?for?all?PersistenceManager.?It?provides
*?method?to?persist?and?object?and?to?obtain?the?current
*?transaction.
*/
public
?
abstract
?
class
?PersistenceManager

{
public
?
static
?PersistenceManager?getInstance()

{
return
?
new
?OJBPersistenceManager();
}
?

public
?
abstract
?
void
?makePersistent(Object?o)
throws
?PersistenceException;?

public
?
abstract
?Transaction?currentTransaction()
throws
?PersistenceException;?

}
?

/**?*/
/**
*?A?Transaction?interface.?It?provides?minimal?support?for
*?beginning,?committing,?and?rolling?back?a?transaction.
*/
public
?
interface
?Transaction

{
public
?
void
?begin()?
throws
?PersistenceException;?

public
?
void
?commit()?
throws
?PersistenceException;?

public
?
void
?rollback()?
throws
?PersistenceException;
}
?

/**?*/
/**
*?An?OJB?specific?implementation?of?the?PersistenceManager
*?class.
*/
public
?
class
?OJBPersistenceManager?
extends
?PersistenceManager

{
private
?PersistenceBroker?broker?
=
?
null
;?

public
?OJBPersistenceManager()

{
broker?
=
?PersistenceBrokerFactory.defaultPersistenceBroker();
}
?

public
?
void
?makePersistent(Object?o)?
throws
?PersistenceException

{
try
{
broker.store(o);
}
catch
?(PersistenceBrokerException?e)

{
//
?rethrow?PersistenceException
}
}
?

public
?Transaction?currentTransaction()?
throws
?PersistenceException

{
return
?
new
?OJBTransaction(broker);
}
}
?

?
/**?*/
/**
*?An?OJB?specific?implementation?of?the?Transaction
*?interface.
*/
public
?
class
?OJBTransaction?
implements
?Transaction

{
private
?PersistenceBroker?broker?
=
?
null
;?

public
?OJBTransaction(PersistenceBroker?broker)

{
this
.broker?
=
?broker;
}
?

public
?
void
?begin()?
throws
?PersistenceException

{
try
{
broker.beginTransaction();
}
catch
(TransactionAbortedException?e)

{
//
?rethrow?PersistenceException
}
catch
(TransactionInProgressException?e)

{
//
?rethrow?PersistenceException
}
}
?

public
?
void
?commit()?
throws
?PersistenceException

{
try
{
broker.commitTransaction();
}
catch
(TransactionAbortedException?e)

{
//
?rethrow?PersistenceException
}
catch
(TransactionNotInProgressException?e)

{
//
?rethrow?PersistenceException
}
}
?

public
?
void
?rollback()?
throws
?PersistenceException

{
try
{
broker.abortTransaction();
}
catch
(TransactionNotInProgressException?e)

{
//
?rethrow?PersistenceException
}
}
}
?

After the above classes are created, it is very simple to convert the test application to use them:
下面是這個Factory的使用:
Example?
14
:?Example?Using?PersistenceManager?and?Transaction?Interfaces
PersistenceManager?pm?
=
?PersistenceManager.getInstance();
Transaction?tx?
=
?pm.currentTransaction();?

tx.begin();
Manager?manager?
=
?newManager();
manager.setName(
"
John?Smith
"
);
manager.setProjectNumber(
new
?Integer(
10
));?

pm.makePersistent(manager);?

Employee?employee?
=
?newEmployee();
employee.setName(
"
David?Cosby
"
);?

pm.makePersistent(employee);?

tx.commit();?

It looks surprisingly like JDO, doesn't it? With a little more effort, you can also hide the OJB query mechanism.
改進建議:
1. 改用抽象工廠方法, 一套持久層產品提供一個工廠,用于創建不同的產品(如:PersistenceManager,Transaction....)
2.考慮從不同的持久層產品中抽取一套通用的持久層接口