简体   繁体   English

内部枚举的策略模式

[英]Strategy pattern with inner enum

I'm trying to get rid of big switch statement from my code and I thought that Strategy pattern based on my existing enum would be nice. 我试图从我的代码中删除大的switch语句,我认为基于我现有的枚举的策略模式会很好。 The concept is like: 这个概念就像:

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

so I can use it like: 所以我可以使用它:

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

but I don't like this part with Option.Option1.setMethodToExecute(this::action1); 但我不喜欢Option.Option1.setMethodToExecute(this::action1); since my enum has more and more options and I would like to have all of this inside enum. 因为我的枚举有越来越多的选择,我想在枚举中拥有所有这些。 What would be perfect is something like this: 什么是完美的是这样的:

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

but this is impossible since enum is static and I don't have access to enclosing instance by MyStrategy.this. 但这是不可能的,因为枚举是静态的,我无法通过MyStrategy.this访问封闭的实例。 I need enum, because I have set of options and it is convenient to use methods like values() or valueOf(), but what I would like to have is single line invoke instead of growing switch. 我需要枚举,因为我有一组选项,并且使用像values()或valueOf()这样的方法很方便,但我想要的是单行调用而不是增长开关。 Do you have any ideas how to achieve sometghing like this or is there any workaround to make this enum constructor call possible Option1(MyStrategy.this::action1) ? 你有任何想法如何实现这样的一些或有没有任何解决方法使这个枚举构造函数调用可能Option1(MyStrategy.this::action1)

With enums you could implement it like this: 使用枚举,您可以像这样实现它:

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

This uses the fact the with lambdas you can make method references to arbitrary instance methods and call them on a specific instance by passing in the instance as first parameter. 这使用lambdas这一事实,您可以对任意实例方法进行方法引用,并通过将实例作为第一个参数传入,在特定实例上调用它们。

you're right. 你是对的。 This isn't possible with enum. 枚举不可能实现这一点。 But why not just use a good old class: 但为什么不用一个好老班:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM