Чего я хотел бы добиться, так это использовать интерфейсы для классов доменов и обобщенные типы c для уровня обслуживания и иметь возможность изменить реализацию уровня постоянства с текущего, который является MongoDb, например, на JPA. Интерфейсы для классов домена необходимы, например, из-за различных аннотаций для JPA и MongoDB (@Entity
и @Document
).
Давайте рассмотрим структуру следующего демонстрационного проекта:
![enter image description here](https://i.stack.imgur.com/085oO.png)
Для каждого элемента модели предметной области может быть три интерфейса, объясним это с помощью пакета user
:
User
- представление объекта предметной области
UserDao
- предоставление методов постоянного уровня
UserService
- предоставление бизнес-логики c методов
Вот интерфейсы для каждого из них:
public interface User {
String getId();
String getFirstName();
String getLastName();
List<Consent> getConsents();
Boolean getBlocked();
}
public interface UserDao <UserType extends User> {
UserType save(UserType user);
Optional<UserType> getById(String userId);
}
public interface UserService <UserType extends User> {
UserType create(String firstName, String lastName);
void addConsent(UserType user, ConsentType consentType);
}
Как я упоминал ранее, текущая реализация этих интерфейсов связана с Mon go DB:
@Getter
@Setter
@Document(collection = "user")
public class MongoUser extends AbstractMongoCollection implements User {
private String firstName;
private String lastName;
private List<PojoConsent> consents;
private Boolean blocked;
void addConsent(PojoConsent consent) {
if(consents == null) {
consents = new ArrayList<>();
}
consents.add(consent);
}
@Override
public List<Consent> getConsents() {
return new ArrayList<>(consents);
}
}
@Component
public class MongoUserDao implements UserDao<MongoUser> {
private MongoUserRepository mongoUserRepository;
@Autowired
public MongoUserDao(MongoUserRepository mongoUserRepository) {
this.mongoUserRepository = mongoUserRepository;
}
@Override
public MongoUser save(MongoUser user) {
return mongoUserRepository.save(user);
}
@Override
public Optional<MongoUser> getById(String userId) {
return mongoUserRepository.findByIdAndDeletedIsFalse(userId);
}
}
@Component
public class MongoUserService implements UserService<MongoUser> {
private UserDao<MongoUser> userDao;
@Autowired
public MongoUserService(UserDao<MongoUser> userDao) {
this.userDao = userDao;
}
@Override
public MongoUser create(String firstName, String lastName) {
MongoUser user = new MongoUser();
user.setBlocked(false);
user.setFirstName(firstName);
user.setLastName(lastName);
user.setDeleted(false);
return userDao.save(user);
}
@Override
public void addConsent(MongoUser user, ConsentType consentType) {
PojoConsent pojoConsent = new PojoConsent();
pojoConsent.setActive(true);
pojoConsent.setType(consentType);
pojoConsent.setDate(LocalDateTime.now());
user.addConsent(pojoConsent);
userDao.save(user);
}
}
Хорошо, так что же проблема? Проблема возникает, когда я внедряю bean-компоненты типа UserDao
и UserService
в другие bean-компоненты (как это происходит в Spring Framework), например EntryPoint
в этом примере (я знаю, что логики c не должно быть) в контроллере пружины, но это только пример):
@RestController
@RequestMapping("/api")
public class EntryPoint {
@Autowired
private ConversationService conversationService;
@Autowired
private UserDao userDao;
@PostMapping("/create/{userId}")
public ResponseEntity<String> createConversation(@PathVariable("userId") String userId) {
Optional<User> optionalUser = userDao.getById(userId);
if(optionalUser.isPresent()) {
User user = optionalUser.get();
Conversation conversation = conversationService.create(user, "default");
return ResponseEntity.ok(conversation.getId());
}
return ResponseEntity.notFound().build();
}
}
Интерфейсы ConversationService
и UserDao
имеют тип generi c, поэтому появляются предупреждения:
![enter image description here](https://i.stack.imgur.com/QimkC.png)
Я не хочу отказываться от универсальных c типов, но, с другой стороны, я знаю, что инъекции без универсальных c типов будет вызывать предупреждения, которые не соответствуют принципам чистого кода. Это правда, что этот дизайн будет работать, несмотря на предупреждения. Я не хочу менять реализацию EntryPoint
, когда я изменяю уровень персистентности с MongoDb на JPA, я просто хочу предоставить новую реализацию для доменных интерфейсов (User
, UserDao
, UserService
et c. )
Как решить проблему с интерфейсом для классов доменов домена и инъекций без универсального c типа?