Zauważyłem, że moja klasa która zawiera w sobie CRUDowe operacje, w każdej metodzie powtarza jeden i ten sam blok try/catch gdzie tak naprawdę różni się tylko jedna linijka no i zwracany typ. Przykładowo, operacja zapisu wygląda w ten sposób:
public Integer save(T objectToSave) {
Session session = null;
Optional<T> optionalObject = null;
Integer savedObjectID = 0;
try {
session = HibernateUtils.getSessionFactory().openSession();
session.beginTransaction();
savedObjectID = (Integer) session.save(objectToSave);
session.getTransaction().commit();
} catch (Exception sqlException) {
if (session.getTransaction() != null) {
session.getTransaction().rollback();
sqlException.printStackTrace();
}
} finally {
session.close();
}
return savedObjectID;
}
Nie wiem czy w takim wypadku taki kod powinno się refaktoryzować? Jeśli tak to w jaki sposób? Wymyśliłem coś takiego, żeby stworzyć interfejs generyczny CRUDOperation który będzie zawierał w sobie metodę execute(Session session); i dla każdej operacji stworzyć klasę która będzie go implementowała. Stworzyłbym też klasę CRUDStrategy gdzie również byłaby metoda execute(CRUDOperation operation) w której zamieścił bym blok try/catch i tam wywoływał interesującą mnie operację. Wyglądałoby to mniej więcej tak:
public interface IOperations {
void excecute(Session session);
}
public class AddingOperation<T> implements IOperations{
private T objectToSave;
public AddingOperation(T objectToSave) {
this.objectToSave = objectToSave;
}
@Override
public void excecute(Session session) {
session.save(objectToSave);
}
}
public class CRUDStrategy<T> {
public void execute(IOperations operation) {
Session session = null;
Optional<T> optionalObject = null;
Integer savedObjectID = 0;
try {
session = HibernateUtils.getSessionFactory().openSession();
session.beginTransaction();
operation.excecute(session);
session.getTransaction().commit();
} catch (Exception sqlException) {
if (session.getTransaction() != null) {
session.getTransaction().rollback();
sqlException.printStackTrace();
}
} finally {
session.close();
}
}
}
I miejsce wywołania:
CRUDStrategy<Quote> strategy = new CRUDStrategy<>();
strategy.execute(new AddingOperation<Quote>(quote));
Czy takie rozwiązanie ma sens? Czy warto dla każdej operacji tworzyć nową klasę i później jej instancję żeby nie powtarzać tego bloku try/catch jak to było przed zmianą? No i zostaje jeszcze kwestia zwracanego typu. Dla zapisu jest przecież typ liczbowy ale dla operacji odczytu jest to obiekt. Jak sobie z tym poradzić albo czy w ogóle warto zaprzątać sobie tym głowę? Może lepiej zostawić tak jak było, z jedną klasą i powtarzającym się kodem?