- Java 8:Lambda 序列化?
- Java 8 lambda 最佳实践
- Java 8 lambda 表达式 10 个示例
- Java8 lambda 表达式 10 个示例
- Java8 Lambda 表达式和流操作如何让你的代码变慢 5 倍
- Java8:Lambda 表达式增强版 Comparator 和排序
- Java 8 LongAdders:管理并发计数器的正确方式
- Java 8 Optional 类深度解析
- Java8 中的 java.util.Random 类
- Java8 中的简易并发
- Java8 学习:Lambda 表达式、Stream API 和功能性接口 — 教程、资源、书籍和实例
- Java8 并发教程:Threads 和 Executors
- Java 8 新特性之旅:使用 Stream API 处理集合
- Java 8 新特性探究(一)通往 lambda 之路_语法篇
- Java 8 新特性探究(六)泛型的目标类型推断
- Java 8 新特性探究(七)深入解析日期和时间-JSR310
- Java 8 新特性探究(八)精简的 JRE 详解
- Java 8 新特性探究(九)跟 OOM:Permgen 说再见吧
- 总结
- Java 8 新特性探究(十)StampedLock 将是解决同步问题的新宠
- Java 8 新特性探究(十一)Base64 详解
- Java 8 新特性探究(十二)Nashorn :新犀牛
- Java 8 新特性终极指南
- Java 8 新的时间日期库的 20 个使用示例
- Java8 日期时间(Date Time)API 指南
- Java8 本地缓存
- Java 8 的 default 方法能做什么?不能做什么?
- Java 8 的 6 个问题
- Java 8 简明教程
- Java8 集合中的 Lambda 表达式
- Java SE 8 新的时间和日期 API
- 在 Java 8 下更好地利用枚举
- 在 Java 8 中避免 Null 检查
- 鲜为人知的 Java8 特性:泛化目标类型推断
在 Java 8 下更好地利用枚举
在我们的云使用分析 API 中,返回了格式化过的分析数据(这里指生成分析图)。最近,我们添加了一个特性,允许用户选择时间段(最开始只可以按天选择)。问题是,代码中每天中的时间段部分高度耦合了……
例如,下面这段代码:
private static List<DataPoint> createListWithZerosForTimeInterval(DateTime from,
DateTime to,
ImmutableSet<Metric<? extends Number>> metrics) {
List<DataPoint> points = new ArrayList<>();
for (int i = 0; i <= Days.daysBetween(from, to).getDays(); i++) {
points.add(new DataPoint().withDatas(createDatasWithZeroValues(metrics))
.withDayOfYear(from.withZone(DateTimeZone.UTC)
.plusDays(i)
.withTimeAtStartOfDay()));
}
return points;
}
注意: Days、Minutes、Hours、Weeks 和 Months 一样出现在代码的后面部分。这些代码来自 Joda-Time Java 时间和日期 API 。甚至方法的名字都没有反应出(各自的功能)。这些名字牢牢的绑定到了 days 的概念上。
我也尝试过使用不同时间段方式(比如月、周、小时)。但我看到了糟糕的 switch/case 鬼鬼祟祟地隐藏在代码里。
你需要知道, switch/case=罪恶 已经深入我心了。在我大学期间的两段实习经历中就已经这么认为了。因此,我会不惜任何代价避免使用 switch/case。这主要是因为它们违反了开放闭合原则 。我深深地相信,遵循这个原则是写出面向对象代码的最好实践。我不是唯一一个这样想的,Robert C. Martin 曾经说:
在很多方面,开放闭合原则是面向对象设计的核心。遵循这个原则会从面向对象技术中收获巨大的好处,比如可重用性和可维护性1 。
我告诉自己:“我们使用 Java8 或许可以发现一些新的特性来避免 swtich/case 的危险场面出现”。使用 Java8 的新 functions (不是那么新,不过你知道我的意思)。我决定使用枚举代表不同的可得到时间段。
public enum TimePeriod
{
MINUTE(Dimension.MINUTE,
(from,
to) -> Minutes.minutesBetween(from, to).getMinutes() + 1,
Minutes::minutes,
from -> from.withZone(DateTimeZone.UTC)
.withSecondOfMinute(0)
.withMillisOfSecond(0)),
HOUR(Dimension.HOUR,
(from,
to) -> Hours.hoursBetween(from, to).getHours() + 1,
Hours::hours,
from -> from.withZone(DateTimeZone.UTC)
.withMinuteOfHour(0)
.withSecondOfMinute(0)
.withMillisOfSecond(0)),
DAY(Dimension.DAY,
(from,
to) -> Days.daysBetween(from, to).getDays() + 1,
Days::days,
from -> from.withZone(DateTimeZone.UTC)
.withTimeAtStartOfDay()),
WEEK(Dimension.WEEK,
(from,
to) -> Weeks.weeksBetween(from, to).getWeeks() + 1,
Weeks::weeks,
from -> from.withZone(DateTimeZone.UTC)
.withDayOfWeek(1)
.withTimeAtStartOfDay()),
MONTH(Dimension.MONTH,
(from,
to) -> Months.monthsBetween(from, to).getMonths() + 1,
Months::months,
from -> from.withZone(DateTimeZone.UTC)
.withDayOfMonth(1)
.withTimeAtStartOfDay());
private Dimension<Timestamp> dimension;
private BiFunction<DateTime, DateTime, Integer> getNumberOfPoints;
private Function<Integer, ReadablePeriod> getPeriodFromNbOfInterval;
private Function<DateTime, DateTime> getStartOfInterval;
private TimePeriod(Dimension<Timestamp> dimension,
BiFunction<DateTime, DateTime, Integer> getNumberOfPoints,
Function<Integer, ReadablePeriod> getPeriodFromNbOfInterval,
Function<DateTime, DateTime> getStartOfInterval)
{
this.dimension = dimension;
this.getNumberOfPoints = getNumberOfPoints;
this.getPeriodFromNbOfInterval = getPeriodFromNbOfInterval;
this.getStartOfInterval = getStartOfInterval;
}
public Dimension<Timestamp> getDimension()
{
return dimension;
}
public int getNumberOfPoints(DateTime from,
DateTime to)
{
return getNumberOfPoints.apply(from, to);
}
public ReadablePeriod getPeriodFromNbOfInterval(int nbOfInterval)
{
return getPeriodFromNbOfInterval.apply(nbOfInterval);
}
public DateTime getStartOfInterval(DateTime from)
{
return getStartOfInterval.apply(from);
}
}
通过枚举,我就能够很容易地修改代码,允许用户给图表数据点指定时间段。
原来是这样调用:
for (int i = 0; i <= Days.daysBetween(from, to).getDays(); i++)
变成这样调用:
for (int i = 0; i < timePeriod.getNumberOfPoints(from, to); i++)
支持 getGraphDataPoints 调用的 Usage Analytics 服务代码已经完成了,并且支持时间段。值得一提的是,它考虑了我之前说过的开放闭合原则。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论