1

私のアプリには、タスクを表すオブジェクトがあります(DBに保存されています)。タスクの実際の実装(いくつかのビジネスロジック)を持つオブジェクトもあります-それらをランナーと呼びましょう。したがって、ランナーは次のインターフェースを実装できます。

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」メソッドを持たせることです(メソッドを実装する必要がある新しいタスクを追加して、忘れられないようにします)が、残念ながらプロジェクトの依存関係のため、タスクオブジェクトはランナーについて何も知ることができません。

良い方法でそれを行う方法に関するアイデアはありますか?

ところで:私はSpringを使用しているので、渡されたタスクに基づいてランナーBeanを取得する方がさらに良いでしょう。

4

3 に答える 3

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);

また、新しい Task タイプを追加すると、そのaccept()メソッドを実装する必要があり、これにより、ビジターに新しいメソッドを追加する必要があり、新しい Runner 実装が必要になります。

于 2013-02-26T13:53:31.430 に答える
1

Beanの命名規則に従う場合、たとえばrunnerBeanName = class name +'Runner'は、ファクトリとしてTask使用できます。ApplicationContextRunner

例えば:

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;

    }
}

エイリアスを使用して、1つのランナーを多くのタスクにバインドできます。

Springに結合されたファクトリが気に入らない場合は、Bean名によってコンテキストMap<String, Runner>内のすべてが注入されるaを自動配線することもできます。Runners

于 2013-02-26T16:19:52.283 に答える
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'全体が標準のmap#getでラップされるようになりました

于 2013-02-26T13:52:29.670 に答える