Spring - 基于枚举的动态工厂

时间:2013-10-03 09:17:43

标签: java spring enums factory

我有以下课程:

public enum TaskType {

    VERIFY_X_TASK, COMPUTE_Y_TASK, PROCESS_Z_TASK;
}

public interface Task{
    void process();
}

@Component
public class VerifyXTask implements Task{
    // Similar classes for the other types of tasks
    public void process() {
    }
}

@Component
public class TaskFactory{
    private Map<TaskType, Task> tasks;
    public Task getTask(TaskType type){
        return tasks.get(type); // return a singleton with all it's fields injected by the application context
    }
}

class UseTool{
    @Autowired
    private TaskFactory taskFactory;

    public void run(String taskType){
        Task task = taskFactory.getTask(TaskType.valueOf(taskType));
        task.process();
    }
}

将TaskType和Task之间的关联注入工厂的最优雅方法是什么? 考虑到有近100种任务类型,这些类型可能会经常发生变化。

- 进一步说明: 我可以在TaskFactory类中使用smth:

tasks.put(TaskType.VERIFY_X_TASK, new VerifyTask());
tasks.put(TaskType.COMPUTE_Y_TASK, new ComputeTask());
tasks.put(TaskType.PROCESS_Z_TASK, new ProcessTask());

但是这不会在Task对象中注入任何属性。

2 个答案:

答案 0 :(得分:2)

我建议采用以下方法:

  1. 定义一个以@ImplementsTask为参数的自定义注释TaskType,以便您可以像这样编写实现类:

    @Component
    @ImplementsTask(TaskType.VERIFY_X_TASK)
    public class VerifyXTask implements Task {
    ...
    

    (或者您可以对@Component进行元注释,以避免在所有类中使用它。)

  2. 将所有已识别的Task个对象注入您的工厂:

    @Autowired
    private Set<Task> scannedTasks;
    
  3. 在工厂的@PostConstruct方法中,迭代scannedTasks中的每个元素,读取注释值并添加Map条目(到{{1} }}, 当然)。您需要决定如何处理给定EnumMap的重复实现。

  4. 这将需要在出厂设置中进行一些反射工作,但这意味着您只需使用适当的值注释TaskType实现,并在没有任何额外工作的情况下扫描它。

答案 1 :(得分:0)

我遇到了类似的问题要解决,我真正要做的是,这可能会有所帮助。

定义任务枚举之类。

public enum Tasks {
    Task1(SubTasks.values());

    Tasks(PagesEnumI[] pages) {
        this.pages = pages;
    }

    PagesEnumI[] pages;
    // define setter and getter
}

定义的子任务,如


public interface PagesEnumI {
    String getName();
    String getUrl();
}

public enum SubTasks implements PagesEnumI {
    Home("home_url");

    SubTasks(String url) {
        this.url = url;
    }

    private String url;

    @Override
    public String getUrl() {
        return url;
    }

    @Override
    public String getName() {
        return this.name();
    }
}

每个子任务枚举调用的定义服务,如


public interface PageI {
    void process();
    Sites getTaskName();
    PagesEnumI getSubTaskName();
}

@Component
public class Home implements PageI {

    // function per SubTask to process
    @Override
    public void process() {}

    // to get the information about Main Task
    @Override
    public Tasks getTaskName() {
        return Tasks.Task1;
    }

    // to get the information about Sub Task
    @Override
    public PagesEnumI getSubTaskName() {
        return Task1.Home;
    }
}

定义一个工厂,例如...


@Component
public class PageFactory {

    Set<PageI> pages;
    // HashMap for keeping objects into
    private static HashMap<String, PageI> pagesFactory = new HashMap<>();

    @Autowired
    public void setPages(Set<PageI> pages) {
        this.pages = pages;
    }

    // construct key by 
    private static String constructKey(Tasks taks, PagesEnumI page) {
        return task.name() + "__" + page.getName();
    }

    // PostConstruct means after construct class object this method should get run
    // iterating over all pages and storing into Map
    @PostConstruct
    private void postConstruct() {
        for (PageI pageI : pages) {
            pagesFactory.put(constructKey(pageI.getTaskName(), pageI.getSubTaskName()), pageI);
        }
    }

    // getting object from factory
    public PageI getPageObject(Tasks task, PagesEnumI page) {
        return pagesFactory.get(constructKey(task, page));
    }
}

到目前为止,我们已经注册了枚举(Tasks和SunTasks)及其服务(带有Tasks和SubTasks的getter),现在定义了一个工厂来调用服务process方法。



@SpringBootApplication
public class Application implements CommandLineRunner {

    PageFactory factory;

    @Autowired
    public void setFactory(PageFactory factory) {
        this.factory = factory;
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        // for each task we might have different sub task
        Arrays.stream(Tasks.values()).forEach(
            task -> {
                // for each and subtask of a task need to perform process
                for (PagesEnumI page : task.getPages()) {
                    PageI pageI = factory.getPageObject(task, page);
                    pageI.process();
                }
            }
        );
    }
}

这不是完全相似的问题,解决它的方法可能相似。因此,我认为将其放在此处可能会有所帮助。请不要输入名称,而只是试图理解概念。如果有人有更多意见,请分享。