ホームページ  >  記事  >  Java  >  Java 8 での enum の有効活用

Java 8 での enum の有効活用

伊谢尔伦
伊谢尔伦オリジナル
2016-11-26 09:46:231359ブラウズ

クラウド使用状況分析 API では、フォーマットされた分析データが返されます (ここでは分析グラフの生成を指します)。最近、ユーザーが期間を選択できる機能を追加しました (当初は日単位のみ)。問題は、コード内の毎日の期間が高度に結合していることです...

Java 8 での enum の有効活用

たとえば、次のコード:

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;
}

注: 日、分、時間、週、月は、コード部分の裏側。このコードは、Joda-Time Java 時刻と日付 API からのものです。メソッドの名前さえも (それぞれの機能を) 反映していません。これらの名前は曜日の概念としっかりと結びついています。

さまざまな期間 (月、週、時間など) も試してみました。しかし、コード内に不正なスイッチ/ケースが潜んでいるのを見たことがあります。

switch/case=sin が私の心に深く浸透していることを知っておく必要があります。私は大学時代の2回のインターンシップ経験ですでにそう思っていました。したがって、スイッチ/ケースは絶対に避けたいと思います。これは主に、オープンクローズの原則に違反しているためです。私は、この原則に従うことがオブジェクト指向コードを記述するためのベスト プラクティスであると強く信じています。このように考えるのは私だけではありません。ロバート C. マーティンはかつてこう言いました。

多くの点で、オープンクローズの原則はオブジェクト指向設計の中核です。この原則に従うと、再利用性や保守性など、オブジェクト指向技術から多大なメリットが得られます1。

私は自分にこう言い聞かせました。「Java8 を使用して、危険な switch/case 状況を回避できるいくつかの新機能を発見できるかもしれません。」 Java 8 の新しい機能を使用してください (それほど新しい機能ではありませんが、私が言いたいことはわかるでしょう)。利用可能なさまざまな期間を表すために列挙型を使用することにしました。

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 呼び出しをサポートする使用状況分析サービス コードが完成し、期間をサポートします。先ほど述べたオープンクローズの原則が考慮されていることは言及する価値があります。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。