I have the following chunk of header and footer code appearing in alot of methods. Is there a cleaner way of implementing this?
Session sess = factory.openSession();
Transaction tx;
try {
tx = sess.beginTransaction();
//do some work
...
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
throw e;
}
finally {
sess.close();
}
The class in question is actually an EJB 2.0 SessionBean which looks like:
public class PersonManagerBean implements SessionBean {
public void addPerson(String name) {
// boilerplate
// dostuff
// boilerplate
}
public void deletePerson(Long id) {
// boilerplate
// dostuff
// boilerpl开发者_如何学Goate
}
}
If you can fit the // do some work
into a strategy pattern, you could create a method containing your boilerplate code passing the action as parameter;
void executeWork(WorkInterface work) {
Session sess = factory.openSession();
Transaction tx;
try {
tx = sess.beginTransaction();
work.execute();
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
throw e;
}
finally {
sess.close();
}
This pattern will fit as long as you do not have to pass many parameters into the execute()
method.
You could introduce an abstract class that collects all this boilerplate stuff. Advantage: avoids unnecessary duplication of code. Here's one approach:
public abstract AbstractBase {
public void doSomthing() {
Session sess = factory.openSession();
Transaction tx;
try {
tx = sess.beginTransaction();
doStuff();
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
throw e;
}
finally {
sess.close();
}
}
public abstract void doStuff();
}
Your implementations simply subclass AbstractBase
and implement the doStuff()
method
private void withTransactedSession(Runnable runnable)
{
Session sess = factory.openSession();
Transaction tx;
try {
tx = sess.beginTransaction();
runnable.run();
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
throw e;
}
finally {
sess.close();
}
}
...
withTransactedSession(new Runnable()
{
public void run()
{
//do some work
...
}
});
You can use your own interface instead of Runnable
if you need to throw specific exceptions.
You probably want something like:
final Session sess = factory.openSession();
try {
boolean committed = false;
final Transaction tx = sess.beginTransaction();
try {
//do some work
...
tx.commit();
committed = true;
} finally {
if (!committed) {
tx.rollback();
}
}
} finally {
sess.close();
}
I've taken the liberty of rolling back no matter what exception, and avoided the issue about which checked exceptions to declare. As Vincent and Robert's answers mention, using the Execute Around idiom allows you to write the code once (although it's still highly verbose).
精彩评论