2013-02-26 66 views
1

在我的應用程序中有表示任務的對象(存儲在數據庫中)。 也會有對象具有實際的任務執行(一些業務邏輯) - 讓我們稱他們爲跑步者。 所以運動員可以即實現以下接口:需要Java模式:基於其他對象的類實例化對象

public interface Runner<T> { 
    void run(T task); 
} 

給定任務目標,我需要一些很好的方式,創建/獲得亞軍,這樣我可以運行它。

我寧願避免像

if(task instance of DoSomethingTask) { 
    return new DoSomethingTaskRunner(); 
} else if(task instance of DoSomethingElseTask) { 
    return new DoSomethingElseRunner(); 
} 

因爲那時每當我創建一個新的亞軍我還需要記住另添加的if/else以上塊。這將是很好,只是自動獲得一個實現了亞軍

Runner<myTask.getClass()> // pseudocode ;) 

這樣做將是使任務有一個「getRunner」的方法(添加新任務的一個很好的方式,我需要實現的方法,所以我不能忘記它),但不幸的是,由於項目依賴關係,我的Task對象無法知道任何關於Runners的內容。

有關如何以一種很好的方式做到這一點的任何想法?

btw:我使用的是Spring,所以根據傳遞的任務得到一個Runner bean會更好。

+0

如何使用Class.forName()動態創建跑步者?這樣你只需要在任務 – yurib 2013-02-26 13:43:18

+0

Erm中存儲跑步者類名,這就是界面的全部要點。你不必知道具體的類是什麼。 – 2013-02-26 13:43:19

回答

1

如果您遵循bean命名約定,例如runnerBeanName = Task class name +'Runner',則可以使用ApplicationContext作爲Runner工廠。

例如:

public class RunnerFactory implements ApplicationContextAware { 

    private ApplicationContext applicationContext; 

    public Runner getRunner(Task task) { 
     return (Runner) applicationContext.getBean(task.getClass().getSimpleName() + "Runner"); 
    } 

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
     this.applicationContext = applicationContext; 

    } 
} 

您可以使用別名來一個亞軍綁定到許多任務。

如果您不喜歡與Spring耦合的工廠,您還可以自動裝入一個Map<String, Runner>,將根據bean名稱在上下文中注入所有Runners

+0

謝謝你,我接受這個答案,因爲它很簡單,每當我添加一個新的亞軍時,我不需要改變任何其他類。我只是使用這樣的事情: @Component(MyTask.class + RUNNER_BEAN_NAME_SUFFIX) 公共類MyTaskRunner實現TaskRunner ...這種方式當我更改任務類的名稱時,runner bean名稱也會自動更改:) – machinery 2013-03-06 16:26:27

0

唔...讓地圖,如:

Map<Class<? extends MyTask>, MyRunner> runners; 

然後在XML或@Configuration添加映射。在方法getRunner(Class<? extends MyTask> myTask)只是:

MyRunner getRunner(Class<? extends MyTask> myTask){ 
    return runners.get(myTask); 
} 

就是這樣。整個'ifology'現在被標準地圖包裹#獲取

+1

感謝您的回答,我決定接受Jose的回答,因爲這樣我不必更新任何其他類 - Runner類中的所有更改。 – machinery 2013-03-06 16:29:49

4

您需要一個RunnerFactory。如果你不想要測試類的任務,你可以使用訪問者模式,它允許基本上是做你想要什麼(myTask.createRunner()),但沒有任務和亞軍之間的耦合:

public interface TaskVisitor<R> { 
    R visitTask1(Task1 task1); 
    R visitTask2(Task2 task1); 
} 

public interface Task { 
    // ... 
    <R> R accept(TaskVisitor<R> visitor); 
} 

public class Task1 implements Task { 
    // ... 
    @Override 
    public <R> R accept(TaskVisitor<R> visitor) { 
     return visitor.visitTask1(this); 
    } 
} 

public class Task2 implements Task { 
    // ... 
    @Override 
    public <R> R accept(TaskVisitor<R> visitor) { 
     return visitor.visitTask2(this); 
    } 
} 

public class RunnerFactory implements TaskVisitor<Runner> { 
    @Override 
    public Runner visitTask1(Task1 task1) { 
     return new Task1Runner(task1); 
    } 

    @Override 
    public Runner visitTask2(Task1 task2) { 
     return new Task2Runner(task2); 
    } 
} 

現在,爲了得到任務的亞軍,你只需要調用

RunnerFactory factory = new RunnerFactory(); 
Runner runner = someTask.accept(factory); 

如果你添加一個新的任務類型,你會foced實施其accept()方法,這將迫使你添加一個新的方法給訪問者,還有一個新的Runner實現。

+0

@JonathanDrapeau:感謝您的編輯。 – 2013-02-26 15:33:33

+0

謝謝,這是一個有趣的模式,這個答案對我來說頗有教育意義。也許我會在將來使用它,但對於我目前的情況,我認爲Jose的解決方案更適合我的問題。 – machinery 2013-03-06 16:23:15