I don't know if it's a good idea to decouple repository from service by introducing an additional layer.
I see these advantages:
-
Easy to add some features such load-balancing, picking a best repository, add cache and other.
-
Repository and service does not coupled to each other
Disadvantages:
- Code harder to understand, because a lot of generic types
- Code harder to write
It's simple example, but it describes what I created.
Entity as interface
interface Book {
Long getId();
String getName();
// other fields related to book entity
}
Jpa implementation:
@Entity
class JpaBook implements Book {
@Id
Long id;
// Implement interface methods
}
Basic persistent operations that used by repository and additional layer
interface BasicBookPersistentOperations<T extends Book> {
void save(T book);
T findById(Long id);
// other methods
}
basic repository interface that used to call the database or use in memory database
interface BookRepository<T extends Book> extends BasicBookPersistentOperations<T> {
String getRepositoryType(); // String for simplicity, can be JPA, IN_MEMORY, REDIS, whatever
}
Jpa book repository that use jpa spec to call the database
interface JpaBookRepository extends BookRepository<JoaBook>, JpaRepository<JpaBook, Long> {
}
And additional layer between repo and service is storage:
// PersistableBook is used as wrapper that does not depend on specific Book implementation
class PersistableBook implements Book {
// Implement methods from interface
}
interface BookStorage extends BasicBookPersistentOperations<PersistableBook> {}
And then I implement BookStorage, for example, simple impl that delegates to repository
class RepositoryDelegateBookStorage implements BookStorage {
final BookRepository<Book> delegate;
public RepositoryDelegateBookStorage(BookRepository<? extends Book> delegate) {
this.delegate = (BookRepository<Book>) delegate; // I don't think it's a good idea to cast it, but if don't do this code will become more complicated
}
@Override
void save(PersistableBook persistableBook ) {
Book book = convertBookToSpecificEntityImpl(persistableBook);
delegate.save(book);
}
@Override
public PersistableBook findById(Long id) {
Book book = delegate.findById(id);
return bookToPersistableBook(book); // Instead of internal methods can be creadted
// EntityConverter, but for simplicity I use internal methods
}
}
I don't know if it's a good or no, can be this refactored to become better? Or it is a complex and should be avoided? Should entities be described using interface and then implemented by different database providers or I should use single class for every database, for example, Redis, Postgres and In memory? What patterns I can use to make code better and easy to extend?
If my question is not clear I can provide more info, thanks!
Aucun commentaire:
Enregistrer un commentaire