具有多个实现的Java通用接口

4
我有以下情景:
public abstract class BaseTask{...}

public class TaskA extends BaseTask {....}

public class TaskB extends BaseTask {....}

public interface TaskService<T extends BaseTask>{
        void process(T task);
}

@Service @Qualifier("taskServiceA")
public class TaskServiceA<TaskA> implements TaskService<TaskA>{
}

@Service @Qualifier("taskServiceB")
public class TaskServiceB<TaskB> implements TaskService<TaskB>{
}

public class ProcessingService{

        @Autowired @Qualifier("taskServiceA")
        private TaskService<TaskA> taskAService;

        @Autowired @Qualifier("taskServiceB")
        private TaskService<TaskB> taskBService;

        public void process(Order o){
            BaseTask task = o.getTask();
            getTaskService(o).start(task);
        }

        private <T extends BaseTask> TaskService<T> getTaskService(Order o){
            if("atype".equals(o.type)){
              return (TaskService<T>) taskAService;
            } else if("btype".equals(o.type)){
              return (TaskService<T>) taskBService;
            }
        }
}

更新:我已经重新措辞了问题,因为我得到的答案不是我想要的。

我的问题与getTaskService方法有关。

  1. 为什么我需要像这样强制转换返回值:

    return (TaskService) taskAService;

  2. 是否有另一种实现getTaskService()方法的方式,而不必进行强制转换?

如果有人能提供一些解释或更好的getTaskService方法实现,我将非常感激。


这段代码似乎无法编译。 - Andrew Tobilko
1
不要在String中使用==,应该使用switch语句或.equals() - Maurice Perry
@AndrewTobilko 我刚刚写了伪代码,以便能够提出我的问题。 - Muneer Y
@MauricePerry,我根据您的评论更新了我的代码。 - Muneer Y
2个回答

1

因为类型T在方法使用的地方被解析。以下语句是有效的:

    TaskService<TaskA> s = getTaskService(o);

所以是:

    TaskService<TaskB> s = getTaskService(o);

在getTaskService方法中,你对T了解得不多。

正确的做法是:

private TaskService<? extends BaseTask> getTaskService(Order o) {
    if ("atype".equals(o.type)) {
        return taskAService;
    } else if ("btype".equals(o.type)) {
        return taskBService;
    } else {
        return null;
    }
}

上面的任务将需要变成:

TaskService<? extends BaseTask> s = getTaskService(o);

1

这个怎么样?

  • 不需要任何if条件。
  • 以后如果有人添加了另一个BaseTask的实现,他们不需要更改任何其他代码。
  • 我建议将"atype"更改为枚举类型,并使用Map<EnumTask, ? extends BaseTask> serviceMap;而不是字符串。

您最终调用Tasks时可以不进行任何检查。

@Service
class ProcessingService { 

        @Autowired 
        private TaskServiceManager taskServiceManager;

        public void process(Order o){
            taskServiceManager.getServiceTask(o.type).start(task);
        }
}

其他课程
enum ServiceEnum {
    TaskA,
    TaskB
}

public class TaskA extends BaseTask {....}
public class TaskB extends BaseTask {....}

public abstract class TaskService<T extends BaseTask>{

    public TaskService(ServiceEnum serviceEnum, TaskServiceManager taskServiceManager) {
        taskServiceManager.registerTask(serviceEnum, this);
    }
    void process(T task);
}

@Service @Qualifier("taskServiceA")
public class TaskServiceA<TaskA> implements TaskService<TaskA>{
        @Autowired 
        public TaskA(TaskServiceManager taskServiceManager) {
              super(ServiceEnum.TaskA, taskServiceManager);
        }
}

@Service @Qualifier("taskServiceB")
public class TaskServiceB<TaskB> implements TaskService<TaskB>{...}

@Service
class  TaskServiceManager {
    Map<ServiceEnum, ? extends TaskService> serviceMap;

    public <T extends TaskService> void registerTask(ServiceEnum serviceName, T task) {
        if(serviceMap.containsKey(serviceName)) {
            throw new IllegalArgumentException("ServiceName is already in the Map");
        }
        serviceMap.put(serviceName, task);
    }

    public <T extends TaskService> T getServiceTask(ServiceEnum serviceName) {
        if(!serviceMap.containsKey(serviceName)) {
            throw new IllegalArgumentException("ServiceName is not Registered");
        }
        return serviceMap.get(serviceName);
    }
}

@AndrewTobilko 编辑了它,逻辑只能在基类中。这样,子任务将永远不必知道管理器的存在。但是,是的,BaseTask仍然会知道它。 因为Manager类在这里只是一个朋友或助手类型的类,用于跟踪正在运行的不同任务,所以这应该还是可以的。 - Kishore Bandi
孩子们仍然需要一个 TaskServiceManager - Andrew Tobilko
不需要更改,可以像实例化Service类一样实例化它。由于使用了Spring,您只需要用@Service进行注释(已添加到答案中)。基本上是一个单例类,并将Manager类注入BaseTask中。 如果使用Spring,我们可以直接将Manager注入到Base类中,而无需从子类发送它。但如果没有DI框架,则无法工作。有关如何使其更好的建议吗? - Kishore Bandi
任务不是豆子,它们是从订单中提取的。 - Andrew Tobilko
啊,我理解错了。我一直在尝试解决TaskService并使用条件进行识别。现在已经修改以适应TaskService。我会看看是否能够改进答案。 - Kishore Bandi
@BandiKishore 感谢您抽出时间并提供答案。如果您能够解释一下我的两个问题并完善您的代码,我将接受您的答案。 - Muneer Y

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接