2017-07-07 130 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