Java策略模式 - 未选中调用作为

时间:2017-07-07 17:46:33

标签: java generics

我有一项服务,我正在做很多if / else语句所以我发现使用策略模式可以帮助我很多。

我正在使用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。将存储库更改为存储Person不是一个选项,因为我需要每个子类的信息..

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 个答案:

答案 0 :(得分: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);