1

時間間隔を処理するための単純な API を作成しようとしています。(私は joda time を認識しており、それを再発明しようとしているわけではありません。これはむしろ演習です)。

私が達成したいのはこれです:

(1)

assert(from("20:30").to("20:50") == Interval("20:30", "20:50") )
//same thing, but without implicit defs
assert(from(Time(20, 30)).to(Time(20, 50)) == Interval(Time(20, 30), Time(20, 50)))


(2)

assert(from("20:30").forMinutes(10) == from("20:30").to("20:40"))


次のように(1)を実装することができました:(toString、Ordered trait、asoを無視)

case class Time(hour: Int, minute: Int)

case class Interval(start: Time, end: Time)

object Interval {
   case class HalfInterval(half: Time => Interval) {
      def to(time: Time): Interval = half(time)
      def forMinutes(minutes: Int): Interval = ??? 
    }
   def from(start: Time): HalfInterval = HalfInterval(Interval(start, _))
}

object Time {
  def apply(hourMinute: String): Time = {
    val tries = hourMinute.split(":").map(s => Try(s.toInt))
    tries match {
      case Array(Success(hour), Success(minute)) => Time(hour, minute)
      case _ => throw new IllegalArgumentException
    }
  }
  implicit def stringToTime(hourMinute: String) = Time(hourMinute)
}


ただし、(2) (つまり Interval.forMinutes) の実装方法がわかりません。

def forMinutes(minutes: Int): Interval = {
  val time = ?? // Based on what Time object could I construct a new Time object here?
  half(time)
}

これについて頭を包むことはできないようです。
この「HalfInterval」ラッパーTime => Intervalはまったく意味がありますか? 機能概念モデルを念頭に置くのではなく
、呼び出しが計画どおりに機能するように、経験的に設計しました。 このAPIを達成するためのより良い方法はありますか?from(..).to(..)

ありがとう

4

2 に答える 2

3

これは私がすることです:

object Interval {
   case class HalfInterval(start: Time) {
      def to(end: Time): Interval = Interval(start, end)
      def forMinutes(minutes: Int): Interval = to(getEnd(start, minutes))
      private def getEnd(start: Time, minutes: Int) = ??? 
    }
   def from(start: Time): HalfInterval = HalfInterval(start)
}

getEnd() は分のパラメーターを start.minute に追加し、60 で除算し、結果を start.hours に追加し、除算の残りを分に追加し、そこで終了時刻を作成します。(次に、次の日に行く場合に備えて、時間モジュラス 24 を実行することもできます)。

編集: HalfInterval は値クラスである必要がありますが、心配する必要はありません。

于 2013-08-13T17:31:50.953 に答える
1

私はルチアーノに同意しますが、あなたHalfIntervalは箱から少し外れています。

しかし、エンジニアは箱から出してすぐに使えるものを好むので、遊ぶ前に組み立てる必要があるので、ここでは別の角度から説明します。

あなたHalfIntervalが言うには、Interval工場をください。必要な証拠をお渡ししますInterval

ここでは、param タイプを Any に変更しましたが、この場合Either[Int, Time]は、 int が未来の分を意味し、time が終了時刻を表す可能性があります。より一般的には、Any よりも安全なマーカー トレイトである可能性があります。

「開始時刻はどこから来るのですか?」という質問に答えるために、 のクロージャが をfromキャプチャしていることがわかりますstart

import scala.language.implicitConversions
import util._

case class Time(hour: Int, minute: Int) {
  def +(delta: Int) = Time(hour, minute + delta) // TODO overflow minutes
}

case class Interval(start: Time, end: Time)

object Interval {
   case class HalfInterval(half: Any => Interval) {
      def to(time: Time): Interval = half(time)
      def forMinutes(minutes: Int): Interval = half(minutes)
    }
   def from(start: Time) = HalfInterval((arg: Any) => arg match {
     case delta: Int => Interval(start, start + delta)
     case end: Time  => Interval(start, end)
     case _          => throw new IllegalArgumentException
   })
}

object Time {
  def apply(hourMinute: String): Time = {
    val tries = hourMinute.split(":").map(s => Try(s.toInt))
    tries match {
      case Array(Success(hour), Success(minute)) => Time(hour, minute)
      case _ => throw new IllegalArgumentException
    }
  }
  implicit def stringToTime(hourMinute: String) = Time(hourMinute)
}

object Test extends App {
  import Interval._
  assert(from("20:30").to("20:50") == Interval("20:30", "20:50") )
  assert(from("20:30").forMinutes(10) == from("20:30").to("20:40"))
}

署名はより奇妙ですが、コードはより理にかなっています。

object Interval {
   case class HalfInterval(f: (Time=>Time) => Interval) {
      def to(end: Time): Interval = f(_ => end)
      def forMinutes(minutes: Int): Interval = f(_ + minutes)
    }
   def from(start: Time) = HalfInterval((end: Time=>Time) => Interval(start, end(start)))
}

どちらも、開始時刻から終了時刻を作成する方法を知っていますtoforMinutes

これにより、例えばuntil(end: Time)、を簡単に追加できforSeconds(secs: Int)ます。

于 2013-08-14T05:41:10.813 に答える