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つくってみた系エントリなので、もしもっといいものあれば…ご紹介いただければ。