枚举-特定于常量方法的实现及策略枚举

各位读者盆友,晚上好。这里分享下枚举的2种不常见的用法。

代码示例来源于 Thrid Edition
[美] Joshua Bloch 余黎敏译

一、最常用的用法

常见的多事枚举加个构造方法,然后根据所需用即可。eg:

package com.chm.effectivejava.myenum;

/**
 * Author:meice Huang
 * Time: 2020/3/8 下午8:22
 */
public enum Planet {

    MERCURY(3.302e+23, 2.439e6),

    VENUS(4.869e+24, 6.502e6),

    EARTH(5.975e+24, 6.378e6),

    MARS(6.419e+23, 6.378e6),

    JUPITER(1.899e+27, 6.378e6),

    SATURN(5.685e+26, 6.378e6),

    URANUS(8.683e+25, 6.378e6),

    NEPTUNE(1.204e+26, 6.378e6);

    private final double mass;// In kilograms

    private final double radius;// In meters

    private final double surfaceGravity; //In m/s^2

    private static final double G = 6.67E-11;

    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
        this.surfaceGravity = G * mass / (radius * radius);
    }

    public double mass() {
        return mass;
    }

    public double radius() {
        return radius;
    }

    public double surfaceGravity() {
        return surfaceGravity;
    }

    public double surfaceWeight(double mass) {
        return mass * surfaceGravity; // F =ma;
    }
}

二、特定于常量的方法实现

我们用2个版本的Option来阐述:
枚举中声明一个抽象方法,并在特定于常量的类主体中,用具体的方法覆盖每个常量的抽象方法——特定于常量的方法实现:constant-specific method implementation。具体总结见代码。

v1:

package com.chm.effectivejava.myenum;

public enum Operation {
    PLUS, MINUS, TIMES, DIVIDE;

    public double apply(double x, double y) {
        switch (this) {
            case PLUS:
                return x + y;
            case MINUS:
                return x - y;
            case TIMES:
                return x * y;
            case DIVIDE:
                return x / y;
        }
        throw new AssertionError("Unkonwn op:" + this);
    }
    /**
     * 总结
     * 1、增加枚举类型,需要同时在switch中增加,如果忘记会导致计算不准确;
     * 2、:
     */
}

v2:

package com.chm.effectivejava.myenum;

import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 特定于常量的类主体constant-specific class body
 * 特定于常量的方法的实现constant-specific method implementation
 */
public enum OperationV2 {
    PLUS("+") {
        @Override
        public double apply(double x, double y) {
            return x + y;
        }
    },
    MINUS("-") {
        @Override
        public double apply(double x, double y) {
            return x - y;
        }
    },
    TIMES("*") {
        @Override
        public double apply(double x, double y) {
            return x * y;
        }
    },
    DIVIDE("/") {
        @Override
        public double apply(double x, double y) {
            return x / y;
        }
    };

    private final String symbol;

    OperationV2(String symbol) {
        this.symbol = symbol;
    }

    @Override
    public String toString() {
        return symbol;
    }//重写了toString方法,意味着只要打印这个类,就是"+-*/"这种符号了,valueOf()方法就没法用了

    public abstract double apply(double x, double y);

    //注意:这里需要通过命令行运行哈:
    public static void main(String[] args) {
        double number1 = Double.parseDouble(args[0]);
        double number2 = Double.parseDouble(args[1]);
        for (OperationV2 op : values()) {
            String result = String.format("%f %ps %f = %f", number1, op, number2, op.apply(number1, number2));
            System.out.println(result);
        }
    }

    private static final Map<String, OperationV2> stringToEnum = Arrays.stream(values())
            .collect(Collectors.toMap(OperationV2::toString, e -> e));

    public static Optional<OperationV2> fromString(String symbol) {
        return Optional.ofNullable(stringToEnum.get(symbol));
    }

    /**
     * 总结
     * 1、特定于常量的方法的实现,这个在生产代码中少见;个人觉得会让枚举类显得很臃肿,不过确实是一种方案;
     * 2、stringToEnum方法写得很好,用到了java8的知识;
     * 3、fromString用到了Optional<>
     */

}

三、策略枚举Strategy enum

看过那本机械工业出版社的设计模式,里面把设计模式分为三类:创建型、结构型、行为型。Strategy就是策略模式。当时看了也是云里雾里,大体明白,不过还是不知道怎么用。看到这个策略枚举的时候,就清楚了。
这里也有2个版本。
v1:

package com.chm.effectivejava.myenum;

public enum PayrollDay {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY;

    private static final int MINS_PER_SHIFT = 8 * 60;

    int pay(int minutesWorked, int payRate) {
        int basePay = minutesWorked * payRate;
        int overtimePay;
        switch (this) {
            case SATURDAY:
            case SUNDAY:
                overtimePay = basePay / 2;
                break;
            default:
                overtimePay = minutesWorked <= MINS_PER_SHIFT ? 0 : (minutesWorked - MINS_PER_SHIFT) * payRate / 2;
        }

        return basePay = overtimePay;
    }

    /**
     * 总结
     * 1、这段代码很简洁的表明了周内和周末算工资的方式;
     * 2、不足:新增枚举的时候,需要改变switch。
     * 类似这种枚举变化可能性还是很大的,但是频率会很低。最好能做到为每种类型的常量都有对应的报酬方式。
     */
}

v2:

package com.chm.effectivejava.myenum;

public enum PayrollDayV2 {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY(PayType.WEEKEND),
    SUNDAY(PayType.WEEKEND);

    private final PayType payType;

    PayrollDayV2() {
        this.payType = PayType.WEEKDAY;
    }

    PayrollDayV2(PayType payType) {
        this.payType = payType;
    }

    int pay(int minsWorked, int payRate) {
//        return PayType.pay(minsWorked,payRate);//这里虽然不能引用,但是大体就是这个思想
        return 0;
    }

    private enum PayType {
        WEEKDAY {
            @Override
            int overtimePay(int minsWorked, int payRate) {
                return minsWorked <= MINS_PER_SHIFT ? 0 : (minsWorked - MINS_PER_SHIFT) * payRate / 2;
            }
        },
        WEEKEND {
            @Override
            int overtimePay(int minsWorked, int payRate) {
                return minsWorked * payRate / 2;
            }
        };

        abstract int overtimePay(int mins, int payRate);

        private static final int MINS_PER_SHIFT = 8 * 60;

        int pay(int minsWorked, int payRate) {
            int basePay = minsWorked * payRate;
            return basePay + overtimePay(minsWorked, payRate);
        }
    }

    /**
     * 总结:
     * 1、策略模式
     * 2、如果扩展,非常方便且不会出错。加入新冠肺炎疫情期间,居家办公新增了一种考核方式
     * VOVID-19-EXAMINE,
     * 只需要新增一个PayType,重写overtimePay,然后在PayRollDayV2中新增一个常量并指定类型即可。
     *
     */
}

枚举,并非日常所见那么简单。

发布了181 篇原创文章 · 获赞 66 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/meiceatcsdn/article/details/104744859