内部枚举的策略模式

时间:2016-10-07 17:04:04

标签: java design-patterns enums method-reference functional-interface

我试图从我的代码中删除大的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();
    }
}

但这是不可能的,因为枚举是静态的,我无法通过MyStrategy.this访问封闭的实例。我需要枚举,因为我有一组选项,并且使用像values()或valueOf()这样的方法很方便,但我想要的是单行调用而不是增长开关。 您是否有任何想法如何实现这样的问题,或者是否有任何解决方法可以使此枚举构造函数调用成为可能Option1(MyStrategy.this::action1)

2 个答案:

答案 0 :(得分: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);
    }
}

这使用了lambda的事实,你可以对任意实例方法进行方法引用,并通过将实例作为第一个参数传入,在特定实例上调用它们。

答案 1 :(得分:0)

你是对的。枚举不可能实现这一点。但为什么不只是使用一个好老班:

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