LoginSignup
0
0

More than 5 years have passed since last update.

初期化時の優先度情報を隠ぺいするオレオレListを作ってみた。

Last updated at Posted at 2016-07-10

0. 要求

  • 初期化時の並び順を確実にするコレクションが欲しかった。
  • 不慮の書き換えを許さないガチガチのコレクションがほしかった。
    • toSeqとかTraversable内にあるCollectionを再生成する系のメソッドを排除
    • foreach、mapなどで高階関数からは並びが保証された状態での操作は可能
  • 一意性を必ず担保する型にしたかった。(重複排除)
    • Setだと並び順が...
  • 不用意に.par.foreachされたくないコレクションがつくりたかった。

1. 実装

Scalaの場合、traitとかで定義されてるメソッドはスーパークラスにてPrivate化できないので再定義することに。
コレクションをラップした型クラスをつくるにはTraverseを継承すれば楽ちんにつくれるのだが、それをやってしまうとtoSeqとかfoldleftとか余計なお荷物ついてくるのでそれは継承しない。

Priority.scala
import scalaz._
import Scalaz._
/**
  * Priority型クラス
  * 初期化時の情報を絶対保証するクラス
  * @tparam T 順序保証するタイプ
  */
final class Priority[+T](i: Seq[T]) {
  require(i.distinct.length == i.length)

  private[collection] def order[U >: T]: Seq[U] = i

  def isDefine: Boolean = order.nonEmpty

  def apply(index: Int): T = order(index)

  def foreach[U](f: T => U): Unit = order.foreach(f)

  def map[B](f: T => B): Priority[B] = Priority(order.map(f))

  override def toString: String = s"Priority(${order.mkString(",")})"

  override def equals(obj: scala.Any): Boolean = obj match {
    case p:Priority[_] => p.order == order
    case _ => false
  }
}

object Priority {
  def apply[A](i: A*): Priority[A] = new Priority[A](i)
}

1. 使い方

あたまかもSeqであるかのように使えます。
今回は設定が重複しないといった形で作ってはありますが、設定重複したい場合には

// これを取れば、設定重複可能。
require(i.distinct.length == i.length)

としてみるといいかもしれないです。

実際の使い方は、こんな感じになると想定。

case class Plan(){
    def execute():Unit = ???
}

object Plan{
   def apply(planName):Plan = ???
}

class PlanController{
    val defaultPlanPriority:Priority[String] = Priority("plan-a" , "plan-c" , "plan-b" , "plan-default")

    def executePlan(planName:Seq[String]) = Action { implicit request => 
        val priority = Priority(planName:_*)
        // この間に不慮の並び替えは絶対発生しない。
        /* priority.toSeq <- × */
        /* priority.foldleft ... <- x */
        priority.map(Plan.apply).foreach(_.execute())
        Ok("success")
    }

    def executePlanSingle(int priorityNumber) = Action { implicit request => 
        // 1個だけの実行も可能
        defaultPlanPriority(priorityNumber).fold(
           NotFound("plan not found")
        ) { p =>
           p.execute()
           Ok("success") 
        }
    }
}

2. 総まとめ

  • 内部コレクションを隠ぺいできる型クラスがつくれた。
  • 型名を増やすことができるのでとっても、表現力があがった感じがする。
  • デメリット:オレオレなので保守必要
  • デメリット:実装なれてないと頭がとろける。(抽象ともっと仲良くならねば。

オレオレList with Functorつくってみた系エントリなので、もしもっといいものあれば…ご紹介いただければ。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0