我需要 Java 泛型方面的幫助。我的模型是:我有一些擴展 Dto(資料傳輸物件)的類和一些擴展物體的類(我的物件到 DB 的模型)。我有
interface Mapper<D extends Dto, E extends Entity>{
//Convert a Entity to Dto.
D toDto(E entity);
而且我有一些實作這個介面的類(即PersonMapper、BookMapper 等等)。
@Component
public class PersonMapper implements Mapper<PersonDto, PersonEntity> {
//implementation
}
@Component
public class BookMapper implements Mapper<BookDto, BookEntity> {
//implementation
}
我想要做的是使用工廠模式以便在運行時選擇我的映射器,這取決于我傳入輸入的字串。
@Autowired
private PersonMapper personMapper;
@Autowired
private BookMapper bookMapper;
public <D extends Dto, E extends Entity> Mapper<D, E> selectMapper(String entity){
if ("Person".equalsIgnoreCase(entity))
return personMapper;
if("Book".equalsIgnoreCase(entity))
return bookMapper;
...
}
在這種情況下,我有以下編譯錯誤:
Type mismatch: cannot convert from PersonMapper to Mapper<D,E>
我的解決方案:
1)
return (Mapper<D, E>) personMapper;
但我有一個警告:
Type Safety: `Unchecked class from personMapper to Mapper<D,H>`
2)
使用通配符和 castb
public Mapper<Dto, Entity> selectMapper(String entity){
Mapper<? extends Dto, ? extends Entity> toReturn = null;
if ("Person".equalsIgnoreCase(entity))
toReturn = personMapper;
else if("Book".equalsIgnoreCase(entity))
toReturn = bookMapper;
...
return (Mapper<Dto, Entity>) toReturn;
}
但在這種情況下,我還有一次警告:
Type safety: Unchecked cast from Mapper<capture#29-of ? extends Dto,capture#30-of ? extends Entity> to Mapper<Dto,Entity>
它有效,但似乎不是一個干凈的解決方案
3)使用通配符作為回傳型別:
public Mapper<? extends Dto, ? extends HistoryEntity> selectMapper(String entity)
but you know, using wildcard as return type is not recommended at all and also doesn't help me because I would like to use this mapper and call mapper.toDto ensuring that the return type is an something that extends Dto.
====================================================================
I don't explain why If I write a class constructor like that
public Service<D extends Dto, E extends Entity>{
public Service(Mapper<D,E> mapper){
this.mapper = mapper;
}
}
and than I inject (for example) bookMapper it works.
If, instead, the Mapper<D,E> is in return type I cannot do such a kind of operation.
====================================================================
The help that I ask to you is:
how can I write a solution using clean code principles (avoiding compile warnings, sonarlint issue etc.) in order to implement this kind of logic?
Thank you very much, I appreciate a lot if you dedicate a little bit of your time helping me to solve my problem.
uj5u.com熱心網友回復:
那些關于呼叫者而不是你的代碼的變數(D 和 E)。D 和 E 是由呼叫者決定的,所以絕對沒有辦法保證PersonDTO合適。
做到這一點Mapper<? extends DTO, ? extends Entity>(并且沒有變數),并且鑒于這些已經是下限,只是Mapper<?, ?>- 這會起作用,您可以撰寫您的return陳述句而沒有任何強制轉換并且沒有編譯器錯誤或警告。
當然,這意味著呼叫者有一個幾乎沒用的型別。
泛型完全基于“編譯時間/寫入時間”。JVM ( java.exe) 不知道什么是泛型,事實上它們中的大多數都無法在編譯程序中存活下來。泛型的唯一目的是使編譯器標記不正確的代碼并避免一些強制轉換,僅此而已。
將該字串轉換為 Mapper 的性質完全是運行時的。
因此,如果Mapper<?, ?>還不夠,那么您想要的就是不可能的。您需要撰寫編譯/寫入時可檢查的內容,因此在您使用字串的那一刻,這是不可能的。例如,一個方法getPersonMapper()當然可以回傳一個Mapper<PersonDTO, PersonEntity>,沒問題。
更一般地說(呵呵)聽起來你在這里嚴重地重新發明了各種輪子。查看 JDBI、JOOQ 和 Hibernate 的教程,以了解有關通常如何撰寫 Java 代碼以與資料庫互動的一些想法。
uj5u.com熱心網友回復:
工廠模式是通過工廠方法組裝或創建某些東西的模式,在您的情況下,您只需要按名稱獲取相應的映射器,因此有一種簡單的方法可以做到這一點,因為映射器 bean 是自動裝配的,添加String getName()到 Mapper 介面然后實作它用于每個實作,例如在 BookMapper
@Override
public String getName() { return "Book"; }
使用映射器名稱作為鍵和映射器 bean 作為值將映射器 bean 存盤在映射中,然后您可以通過其名稱檢索它:
@Service
public class SimpleService {
private BookMapper bookMapper;
private PersonMapper personMapper;
private Map<String, Mapper<? extends DTO, ? extends Entity>> mappers = new HashMap<>();
public SimpleService(BookMapper bookMapper, PersonMapper personMapper) {
this.bookMapper = bookMapper;
this.personMapper = personMapper;
mappers.put(bookMapper.getName(), bookMapper);
mappers.put(personMapper.getName(), personMapper);
}
public Mapper<? extends DTO, ? extends Entity> getMapperByName(String mapperName) {
return mappers.get(mapperName);
}
}
您可以將其投射到相應的映射器而不會發出警告。
PersonMapper p = (PersonMapper) simpleService.getMapperByName("Person");
或者您可以在他們的服務中放置不同的映射器并使用該服務來處理您喜歡的代碼,畢竟您需要指定的映射器來執行指定的操作:
if(personThings){
personService.doSomeThing();
}
if(bookThings){
bookService.doSomething();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/407138.html
標籤:
