重新学习javaSE——枚举

1.枚举类被编译器自动声明为final,不可被子类继承。枚举类隐式地继承java.lang.Enum,且枚举类中每一个生成的enum元素,都是枚举类中的static & final 枚举类实例,有点像内部类。如果想扩展枚举,只能通过接口实现,枚举默认实现了Comparable接口和序列化接口,可以直接重写其compareTo方法自定义比较逻辑。

2.枚举的ordinal可用于表示枚举的声明次序,极度不推荐使用该方法,因为枚举声明的次序关联性很弱,略有改动就会影响到代码逻辑。values方法可用于遍历所有枚举实例,这个方法也是被编译器隐式声明的。

3.可以通过EnumMap实现简洁的命令模式,EnumMap的key只能是enum实例,配合lambda可读性很高,而且使用EnumMap的效率要比HashMap高。这种解耦if else/switch的方法即所谓的表驱动,适合用来处理大量或多变的条件分支情况。

public enum FoodEnum {
    CHICKEN, MILK, BREAD;

    interface Consumer {
        void doSomething();
    }

    EnumMap map = new EnumMap<>(FoodEnum.class);

    public void init() {
        map.put(CHICKEN, () -> System.out.println("吃鸡肉"));
        map.put(MILK, () -> System.out.println("喝牛奶"));
        map.put(BREAD, () -> System.out.println("吃面包"));
    }
}

4.也可以通过枚举实现策略模式。枚举和普通的对象一样,有属性,同样也可以有行为,比如上面的命令模式,可以将comsumer的操作转为枚举对象的行为,可读性又提高了一些,不过策略枚举只适合实现不那么复杂的行为(比如一些简单的工具类)。如果实现过于复杂,建议使用上面的命令模式,再把实现拆分为多个Comsumer的子类。同理,如果实现很简单,使用策略枚举更好。

public enum FoodEnum {
    CHICKEN {
        @Override
        void doSomething() {
            System.out.println("吃鸡肉");
        }
    }, MILK {
        @Override
        void doSomething() {
            System.out.println("喝牛奶");
        }
    }, BREAD {
        @Override
        void doSomething() {
            System.out.println("吃面包");
        }
    };

    interface Consumer {
        void doSomething();
    }

    abstract void doSomething();

    public static void main(String[] args) {
        Arrays.stream(values()).forEach(FoodEnum::doSomething);
    }

}

5.枚举可以用来实现多路分发,即当输入的n个参数类型不确定时,可能需要编写大量的模板方法去实现,比如java中Number,如果有一个方法计算a.multi(b),当a与b的类型不确定时,必须要考虑short int long double float的几种情况,否则会丢失精度,下面的例子比较简单,直接返回ResultCode的枚举,如果像上面的计算数字,其计算部分的业务逻辑可以用策略模式在ResultCode枚举中实现,枚举实现多路分发的本质就是利用构造器实现一个二维表的结构,第一个参数在方法调用前就已经确定,根据第二个参数的不同选择不同的实现即可。

除了利用枚举来实现两路分发,还可以用二维数组,但最常想到的还是利用Map>的数据结构实现,配合枚举限制参数类型,就变成了Map>,如果有实现多路分发的场景,更推荐使用guava提供的数据结构EnumHashBiMap,可读性更强更加简洁。

public class ItemComparator {
    public enum ResultCode {
        GT, EQ, LT
    }

    public interface Item2> {
        ResultCode compete(T code);
    }

    enum ItemCode implements Item2 {
        // AA  BB  CC
        AA(EQ, GT, LT),
        BB(LT, EQ, LT),
        CC(GT, GT, EQ);
        private ResultCode item1;
        private ResultCode item2;
        private ResultCode item3;

        private ItemCode(ResultCode item1, ResultCode item2, ResultCode item3) {
            this.item1 = item1;
            this.item2 = item2;
            this.item3 = item3;
        }

        /* (non-Javadoc)
         * @see com.demo.multiple.enums.Item2#compete(com.demo.multiple.Item)
         */
        @Override
        public ResultCode compete(ItemCode code) {
            switch (code) {
                case AA:
                    return item1;
                case BB:
                    return item2;
                case CC:
                    return item3;
            }
            return null;
        }
    }

    public static void main(String[] args) {
        Item2 item1 = ItemCode.AA;
        Item2 item2 = ItemCode.CC;
        System.out.println("AA vs CC :" + item1.compete(item2));
    }


}

6.除了以上几种枚举的应用,枚举还可以在内部实现状态机、基于ordinal实现责任链,不过并不算得上常用的方法,这里不再赘述。总的来说,java中的枚举非常强大,但在日常的开发中,绝大多数情况下枚举仅用于表明状态,而非和设计模式搭配起来做这些花里胡哨的事情,见仁见智吧,以前一直觉得java语言的表达能力并不强,但没想到枚举有这么多玩法。

你可能感兴趣的:(JavaSE)