2017-07-07 68 views
2

成員的未經檢查的呼叫我有一個服務,我在做很多if/else語句,所以我發現使用策略模式可以幫助我很多。Java策略模式 - 作爲

我正在與Mongo合作,我需要在數據庫中存儲兩個不同的模型在不同的集合中。這些模型擴展了一些具有一些類似信息的通用模型我開始在運行時決定使用什麼類,但現在我的代碼顯示警告:unchecked call to 'save(T)' as a member of type 'Strategy'

下面是我正在嘗試的代碼。目前,我剛剛添加了一個@SuppressWarnings("unchecked"),目前工作正常,但我想確認這是否會導致問題,以及哪種方法更好。

問題:我該如何解決這個問題?

守則截至目前:

interface Strategy<T extends Person> { 
    T save(T model); 
    //other methods 
} 

class StudentStrategy implements Strategy<Student> { 
    private StudentRepository studentRepository; 

    public Student save(Student student) { 
     return studentRepository.save(student); 
    } 
} 
class TeacherStrategy implements Strategy<Teacher> { 
    private TeacherRepository teacherRepository; 

    public Teacher save(Teacher teacher) { 
     return teacherRepository.save(teacher); 
    } 
} 

class PersonService { 
    void doSomething(Person person) { 
     Strategy strategy = StrategyFactory.getStrategy(person.getType()); 
     strategy.save(person); //THIS LINE SAYS A unchecked call to 'save(T)' as a member of type 'Strategy' 
    } 
} 

class StrategyFactory { 
    public static Strategy getStrategy(PersonType personType) { 
     if(personType == STUDENT) return new StudentStrategy(); 
     if(personType == TEACHER) return new TeacherStrategy(); 
     return null; 
    } 
} 

舊代碼:

這是我以前做的代碼。正如你所看到的,有很多if/else。更改庫存儲的人不是一個選項,因爲我需要每個子類的信息..

class OldPersonService { 
    void doSomething(Person person) { 
     if(person.getType == STUDENT) { 
      studentRepository.save(person); 
     } else { 
      teacherRepository.save(person); 
     } 
     person.setBirthday(new Date()); 
     person.setName("john"); 
     if(person.getType == STUDENT) { 
      studentRepository.findReferals(person); 
     } else { 
      teacherRepository.findReferals(person); 
     } 
    } 
} 
+1

見例如https://stackoverflow.com/q/2770321/2891664和https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html。但是,提出解決方案有點困難,但不知道你在做什麼。實際上,這裏比較傳統的解決方案根本不使用泛型或策略,而是在'Student'和'Teacher'覆蓋的'Person'類中編寫抽象方法。另一種可能性可能像我在這裏的答案中所示:https://stackoverflow.com/a/44422954/2891664。 – Radiodef

+0

hi @Radiodef!我嘗試過使用抽象,問題是,如果我這樣做,我的存儲庫將無法返回每個子類,我將無法訪問它的每個單獨的屬性。但感謝鏈接,它有助於更​​多地瞭解泛型! :) –

+0

可能重複[什麼是原始類型,爲什麼我們不應該使用它?](https://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt -we-use-it) – Tom

回答

4

你的工廠返回原始Strategy:所以

class StrategyFactory { 
    public static Strategy getStrategy(PersonType personType) { 
     if(personType == STUDENT) return new StudentStrategy(); 
     if(personType == TEACHER) return new TeacherStrategy(); 
     return null; 
    } 
} 

爲使用此客戶端類廠家:

Strategy strategy = StrategyFactory.getStrategy(person.getType()); 
strategy.save(person); 

編譯器發出一個警告爲save()設計有通用型工作的方法:

T save(T model); 

在你的情況T應該是StudentTeacher但你沒有在工廠方法指定。

爲確保策略工廠客戶類的類型安全,getStrategy()應該返回一個符合客戶期望的策略。

例如,您可以定義一個作用域方法類型:您使用投策略<T extends Person>

public static <T extends Person> Strategy<T> getStrategy(PersonType personType) { 
     if(personType == STUDENT) return (Strategy<T>) new StudentStrategy(); 
     if(personType == TEACHER) return (Strategy<T>) new TeacherStrategy(); 
     return null; 
    } 
} 

您可以注意到在getStrategy()方法的向下轉換。
如果要定義一個返回Strategy實例的實例,並使用根據客戶端請求更改的泛型類型,那麼這些是不可避免的。
現在,在提供程序類中執行強制轉換總是比在多次執行此操作的客戶機類中執行轉換要好,並且可能會出現錯誤。

通過這種方式,客戶端可以這樣寫:

Strategy<Person> strategy = StrategyFactory.getStrategy(person.getType()); 
strategy.save(person); 
+1

非常感謝!我喜歡你如何製作演員,雖然它仍然顯示出一個無法控制的演員警告,但我可以忽略它,正如你所說的,最好在演員提供演員。非常感謝您的幫助!! –

+0

非常歡迎你,如果我能幫到你,很高興:) – davidxxx

+0

@GhostCat :)噢,這很好:我終於可以打電話給你M. 50K了。真誠的祝賀親愛的同事:) – davidxxx