1

コードから大きな switch ステートメントを取り除こうとしていますが、既存の列挙型に基づく戦略パターンがいいと思いました。コンセプトは次のようなものです。

public class MyStrategy {

    public MyStrategy() {
        Option.Option1.setMethodToExecute(this::action1);
        Option.Option2.setMethodToExecute(this::action2);
    }

    public void executeChoosenMethod(int i) {
        Option.values()[i].execute();
//        instead of
//        switch(convertItoOption()) {
//            case Option1:...
//            case Option2:...
//        }
    }

    private void action1() {
        System.out.println("action1");
    }

    private void action2() {
        System.out.println("action2");
    }

    private enum Option {
        Option1, Option2;

        private InvokeAction methodToExecute;

        public void setMethodToExecute(InvokeAction methodToExecute) {
            this.methodToExecute = methodToExecute;
        }

        public void execute() {
            methodToExecute.execute();
        }
    }

    @FunctionalInterface
    private interface InvokeAction {
        void execute();
    }
}

だから私はそれを次のように使うことができます:

public class StrategyTest {
    public static void main(String[] args) {
        MyStrategy strategy = new MyStrategy();
        //user choose 0 or 1
        strategy.executeChoosenMethod(0);
        strategy.executeChoosenMethod(1);
    }
}

Option.Option1.setMethodToExecute(this::action1);しかし、列挙型にはますます多くのオプションがあり、列挙型の中にすべてを入れたいので、この部分は好きではありません。完璧なのは次のようなものです。

public class MyStrategy {
    public void executeChoosenMethod(int i) {
        Option.values()[i].execute();
    }

    private void action1() {
        System.out.println("action1");
    }

    private void action2() {
        System.out.println("action2");
    }

    private enum Option {
        Option1(MyStrategy.this::action1), 
        Option2(MyStrategy.this::action2);

        private InvokeAction methodToExecute;

        private Option(InvokeAction method) {
            methodToExecute = method;
        }

        public void execute() {
            methodToExecute.execute();
        }
    }

    @FunctionalInterface
    private interface InvokeAction {
        void execute();
    }
}

しかし、enum は静的であり、MyStrategy.this で囲んでいるインスタンスにアクセスできないため、これは不可能です。オプションのセットがあり、values() や valueOf() などのメソッドを使用すると便利なため、enum が必要ですが、スイッチを大きくする代わりに 1 行で呼び出す必要があります。このような何かを達成する方法はありますか、またはこの列挙型コンストラクターの呼び出しを可能にする回避策はありますOption1(MyStrategy.this::action1)か?

4

2 に答える 2

3

列挙型を使用すると、次のように実装できます。

public class MyStrategy {
    public void executeChoosenMethod(int i) {
        Option.values()[i].execute(this);
    }

    private void action1() {
        System.out.println("action1");
    }

    private void action2() {
        System.out.println("action2");
    }

    private enum Option {
        Option1(MyStrategy::action1), 
        Option2(MyStrategy::action2);

        private InvokeAction methodToExecute;

        private Option(InvokeAction method) {
            methodToExecute = method;
        }

        public void execute(MyStrategy s) {
            methodToExecute.execute(s);
        }
    }

    @FunctionalInterface
    private interface InvokeAction {
        void execute(MyStrategy s);
    }
}

これは、ラムダを使用すると、任意のインスタンス メソッドへのメソッド参照を作成し、インスタンスを最初のパラメーターとして渡すことで特定のインスタンスでそれらを呼び出すことができるという事実を利用しています。

于 2016-10-07T18:02:24.003 に答える
0

あなたが正しい。これは enum では不可能です。しかし、古き良きクラスを使用しないのはなぜですか。

public class MyStrategy {

    public MyStrategy() {
        buildUp();
    }

    public void executeChoosenMethod(int i) {
        actions.get(i).execute();
    }

    private void action1() {
        System.out.println("action1");
    }

    private void action2() {
        System.out.println("action2");
    }

    private List<InvokeAction> actions = new ArrayList<>();

    private void buildUp() {
        actions.add(this::action1);
        actions.add(this::action2);
    }

    @FunctionalInterface
    private interface InvokeAction {
        void execute();
    }
}
于 2016-10-07T17:18:48.040 に答える