I am writing a Java application following the MVC pattern, abstract enough to allow the backend to connect to an Sql and a NoSql database. I have 4 model classes and 4 DAO interfaces. Each DAO is implemented in two ways, one for sql and one for mongodb. I want to add a Transaction Manager to execute database operations in atomic transactions: the problem is that these operations involve a variable number of DAOs and I don't know how to implement the Manager with more than one Dao. I'm not using Spring and I'm not willing to add it.
I've had the following ideas but each one has something I'm not sure about:
- Make interfaces `MyDao_X` extend another interface `GenericDao` and use the last one in TransactionCode. This way I wouldn't know which Dao to instantiate in `TransactionManagerMysql`
- Extend Function to be an N-Function which can accept N inputs and produce an output. In this case N = 4, so I could always instantiate all the DAOs. Here the doubts are the following: I don't know how to do and I'm following TDD so I should figure out how to test this extension. Moreover, it doesn't seem very efficient to me to instantiate 4 Dao every time just because I don't know how many or the type I need. Additionally, if the number of Dao changes over time, I would be forced to modify all the functions in Service Layer to adapt the number of inputs to lambdas
What I would do if I had only one Dao
public interface TransactionManager {
<T> T executeTransaction(TransactionCode<T> code);
}
@FunctionalInterface
public interface TransactionCode<T> extends Function<MyDAO, T> {
}
public class ServiceLayer {
private TransactionManager transactionManager;
public ServiceLayer(TransactionManager manager) {
transactionManager = manager;
}
public void doSomethingInTransaction() {
transactionManager.executeTransaction((myDao) -> {
myDao.doSomething();
return null;
});
}
}
public class TransactionManagerMysql implements TransactionManager {
private EntityManager entityManager;
public TransactionManagerMysql(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
public <T> T executeTransaction(TransactionCode<T> code) {
try {
entityManager.getTransaction().begin();
T result = code.apply(new MyDaoSQL(entityManager));
entityManager.getTransaction().commit();
return result;
} catch (Exception e) {
entityManager.getTransaction().rollback();
}
}
}
I was sure I had to extend
Functionto a customN-Functionin order to be able to pass multiple input parameters (because this is how my teacher explained it). Well, I found out that I don't need to useFunction, not even in the single-input scenario. Here the only purpose of extendingFunctionis to invoke its methodapply()fromServiceLayer. Instead of generalising to anN-FunctionI can just define a method with an adeguate number of inputs. To answer my question is enough to rewriteTransactionCodeas follows: