在业务系统中,时间区间对象常用于描述一段连续的时间范围,比如统计某个月的用户活跃数据、设置优惠券的有效使用时段等。不同场景下使用的时间类型可能不同,比如有的是java.time.LocalDate,有的是java.time.LocalDateTime,如果为每个时间类型都单独编写区间构建逻辑,会产生大量重复代码,也不利于后续维护扩展。

核心设计思路
要实现泛型时间区间对象的统一构建,核心分为两步:首先通过接口抽象定义时间区间的通用属性和行为,让所有时间区间对象都遵循统一规范;然后结合模式匹配,针对不同时间类型的特性,适配对应的区间计算逻辑,避免硬编码类型判断。
接口抽象设计
首先定义一个泛型的时间区间接口,泛型参数T约束为可比较的时间类型,接口中包含区间的起始时间、结束时间两个核心属性,以及判断时间是否在区间内、获取区间长度等通用方法。
import java.time.temporal.Temporal;
import java.util.Comparator;
/**
* 泛型时间区间接口,泛型T需为可比较的时间类型
*/
public interface TimeInterval<T extends Temporal & Comparable<? super T>> {
/**
* 获取区间起始时间
* @return 起始时间
*/
T getStart();
/**
* 获取区间结束时间
* @return 结束时间
*/
T getEnd();
/**
* 判断指定时间是否在区间内(包含边界)
* @param time 待判断的时间
* @return 在区间内返回true,否则返回false
*/
default boolean contains(T time) {
return time != null && Comparator.<T>naturalOrder().compare(time, getStart()) >= 0
&& Comparator.<T>naturalOrder().compare(time, getEnd()) <= 0;
}
}
模式匹配适配不同时间类型
Java 17及以上版本支持模式匹配,我们可以通过模式匹配来处理不同时间类型的区间构建逻辑,比如针对LocalDate和LocalDateTime分别实现对应的区间构建器,统一对外暴露构建入口,根据传入的时间类型自动匹配对应的处理逻辑。
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.Temporal;
/**
* 时间区间构建器,通过模式匹配适配不同时间类型
*/
public class TimeIntervalBuilder {
/**
* 构建时间区间对象
* @param start 起始时间
* @param end 结束时间
* @return 对应的泛型时间区间对象
* @throws IllegalArgumentException 如果起始时间晚于结束时间
*/
public static <T extends Temporal & Comparable<? super T>> TimeInterval<T> build(T start, T end) {
if (start == null || end == null) {
throw new IllegalArgumentException("起始时间和结束时间不能为空");
}
if (start.compareTo(end) > 0) {
throw new IllegalArgumentException("起始时间不能晚于结束时间");
}
// 模式匹配适配不同时间类型
if (start instanceof LocalDate && end instanceof LocalDate) {
return (TimeInterval<T>) new LocalDateInterval((LocalDate) start, (LocalDate) end);
} else if (start instanceof LocalDateTime && end instanceof LocalDateTime) {
return (TimeInterval<T>) new LocalDateTimeInterval((LocalDateTime) start, (LocalDateTime) end);
} else {
throw new IllegalArgumentException("不支持的时间类型,当前仅支持LocalDate和LocalDateTime");
}
}
/**
* LocalDate类型的区间实现类
*/
static class LocalDateInterval implements TimeInterval<LocalDate> {
private final LocalDate start;
private final LocalDate end;
public LocalDateInterval(LocalDate start, LocalDate end) {
this.start = start;
this.end = end;
}
@Override
public LocalDate getStart() {
return start;
}
@Override
public LocalDate getEnd() {
return end;
}
}
/**
* LocalDateTime类型的区间实现类
*/
static class LocalDateTimeInterval implements TimeInterval<LocalDateTime> {
private final LocalDateTime start;
private final LocalDateTime end;
public LocalDateTimeInterval(LocalDateTime start, LocalDateTime end) {
this.start = start;
this.end = end;
}
@Override
public LocalDateTime getStart() {
return start;
}
@Override
public LocalDateTime getEnd() {
return end;
}
}
}
实际使用示例
完成上述设计后,我们可以很方便地构建不同时间类型的区间对象,并且统一调用接口定义的方法,不需要关心具体实现细节。
import java.time.LocalDate;
import java.time.LocalDateTime;
public class TimeIntervalDemo {
public static void main(String[] args) {
// 构建LocalDate类型的区间
TimeInterval<LocalDate> dateInterval = TimeIntervalBuilder.build(
LocalDate.of(2024, 1, 1),
LocalDate.of(2024, 1, 31)
);
System.out.println("2024-01-15是否在区间内:" + dateInterval.contains(LocalDate.of(2024, 1, 15)));
// 构建LocalDateTime类型的区间
TimeInterval<LocalDateTime> dateTimeInterval = TimeIntervalBuilder.build(
LocalDateTime.of(2024, 1, 1, 0, 0, 0),
LocalDateTime.of(2024, 1, 1, 23, 59, 59)
);
System.out.println("2024-01-01 12:00:00是否在区间内:" + dateTimeInterval.contains(LocalDateTime.of(2024, 1, 1, 12, 0, 0)));
}
}
方案优势
- 统一规范:所有时间区间对象都遵循
TimeInterval接口的定义,调用方式统一,降低使用成本 - 易扩展:如果需要支持新的时间类型,只需要新增对应的区间实现类,再在构建器的模式匹配逻辑中补充对应分支即可,不需要修改已有代码
- 减少重复:通用的区间判断逻辑都放在接口默认方法中,不同实现类只需要关注自身属性存储即可,避免重复编码