在实际开发中,有各种奇葩的需求,我就遇到一次,在调度任务建依赖的时候,需要选择依赖的周期和周期的值

比如下面这样,如果你依赖天任务,那么还需要选择今天、昨天还是前七天?

周期

周期值

描述

day

today,last7Days,last3Days,last2Days,last1Days

今天、昨天、前两天、前三天、前七天

month

thisMonth,lastMonth,lastMonthBegin,lastMonthEnd

本月、上月、上月初、上月末

week

thisWeek,lastWeek,lastWednesday

本周、上周、上周一~上周日

hour

last3Hours,last24Hours,currentHour,last1Hour

当前小时、前1小时,前2小时,前3小时,前24小时

显而易见,这有两层枚举,关键是怎么实现呢?

枚举类已经有了默认父类,继承是没法考虑了,只能考虑组合

首先定义父类

//日期周期,父枚举
public enum Period {
    DAY("日"),
    MONTH("月"),
    WEEK("周"),
    HOUR("时");

    private String desc;

    Period(String desc) {
        this.desc = desc;
    }

然后定义子类

public enum PeriodValue {
    today("今天", Period.DAY),
    last7Days("前7天", Period.DAY),

    thisMonth("本月", Period.MONTH),
    lastMonth("上月", Period.MONTH),

    thisWeek("本周", Period.WEEK),
    lastWeek("上周", Period.WEEK),

    currentHour("当前小时", Period.HOUR),
    last1Hour("前1小时", Period.HOUR);

    private String desc;
    private Period parent;

    PeriodValue(String desc, Period parent) {
        this.desc = desc;
        this.parent = parent;
    }

    public String getDesc() {
        return desc;
    }

    public Period getParent() {
        return parent;
    }

    /**
     * 方法一:在子枚举定义静态方法,根据父枚举,得到子枚举列表
     *
     * @param parent
     * @return
     */
    public static List<PeriodValue> getPeriodValues(Period parent) {
        return Arrays.stream(PeriodValue.values()).filter(periodValue -> {
            return periodValue.getParent().equals(parent);
        }).collect(Collectors.toList());

    }


    public static void main(String[] args) {
        Period day = Period.DAY;
        //方法一
        List<PeriodValue> periodValues = PeriodValue.getPeriodValues(day);
        System.out.println(day);
        System.out.println(periodValues);
      
    }
}

我们在每个子枚举的属性中标记了子枚举对应的父枚举,进而定义了一个静态方法根据父枚举获取子枚举列表

执行下:

DAY
[today, last7Days]

的确建立了父子枚举的关系

但还有另外一种实现方法,就是通过父枚举直接获取子枚举列表

下面是修改后的父枚举实现:

public enum Period {
    DAY("日"){
        @Override
        List<PeriodValue> getChildren() {
            return Arrays.stream(PeriodValue.values()).filter(periodValue -> {
                return periodValue.getParent().equals(this);
            }).collect(Collectors.toList());
        }
    },
    MONTH("月"){
        @Override
        List<PeriodValue> getChildren() {
            return Arrays.stream(PeriodValue.values()).filter(periodValue -> {
                return periodValue.getParent().equals(this);
            }).collect(Collectors.toList());
        }
    },
    WEEK("周"){
        @Override
        List<PeriodValue> getChildren() {
            return Arrays.stream(PeriodValue.values()).filter(periodValue -> {
                return periodValue.getParent().equals(this);
            }).collect(Collectors.toList());
        }
    },
    HOUR("时"){
        @Override
        List<PeriodValue> getChildren() {
            return Arrays.stream(PeriodValue.values()).filter(periodValue -> {
                return periodValue.getParent().equals(this);
            }).collect(Collectors.toList());
        }
    };

    private String desc;

    Period(String desc) {
        this.desc = desc;
    }

    /**
     * 方法二:在父枚举定义抽象类,直接从父枚举获取子枚举列表
     * @return
     */
    abstract List<PeriodValue> getChildren();

此时就可以通过父枚举直接得到子枚举列表,示例如下

public static void main(String[] args) {
        Period day = Period.DAY;
        //方法一
        List<PeriodValue> periodValues = PeriodValue.getPeriodValues(day);
        System.out.println(day);
        System.out.println(periodValues);
        //方法二
        List<PeriodValue> children = day.getChildren();
        System.out.println(children);
    }

结果是一样的,虽然代码有些冗余,但在使用的时候的确是简单了很多,逻辑也更清晰了。

备注:

方法一其实还有另外一个用途,假如子枚举不仅要根据父枚举进行筛选,还有其他筛选条件,类似于有多个父类

此时还可以在子枚举中可以再标记一个属性,再定义一个静态方法进行多条件筛选,非常灵活,而方法二是实现不了这种多条件筛选的。