2016-03-03 4 views
8

Я пытаюсь моделировать поведение перечисления с использованием объекта case. Он чувствует себя немного многословным, а не изящным, и мне было интересно, есть ли лучший способ достичь этого.Элегантный способ реализации перечисления с использованием объекта case

Так вот пример:

sealed trait Operator 
object Operator{ 
    def apply(value: String) = value match { 
    case EqualsOp.name => EqualsOp 
    case NotEqualOp.name => NotEqualOp 
    case ContainsOp.name => ContainsOp 
    case NotContainsOp.name => NotContainsOp 
    case _ => UnknownOp 
    } 
} 

case object EqualsOp extends Operator { val name = "equals" } 
case object NotEqualOp extends Operator { val name = "not_equals" } 
case object ContainsOp extends Operator { val name = "contains" } 
case object NotContainsOp extends Operator { val name = "not_contains" } 

Есть ли лучший способ получить это обратное преобразование из строки в реальный объект случае? Или вообще лучше реализовать это?

ответ

10

Я предпочитаю такой подход:

sealed case class ProgressStatus(value: String) 

object ProgressStatus { 
    object IN_PROGRESS extends ProgressStatus("IN_PROGRESS") 
    object ACCEPTED extends ProgressStatus("ACCEPTED") 
    object REJECTED extends ProgressStatus("REJECTED") 

    val values = Seq(IN_PROGRESS, ACCEPTED, REJECTED) 
} 

получить значение:

ProgressStatus.IN_PROGRESS.value 

, чтобы получить все значения:

+1

Спасибо! Но это в основном тот же код, что и я. В вашем примере пока еще нет способа сопоставить строку с соответствующим объектом case. – Tomer

+0

Это, например: '' 'ProgressStatus (" ACCEPTED ")' '' соответствует '' 'ProgressStatus.ACCEPTED''' –

+0

Приятный подход !!! – Dani

-2

Я предпочитаю такой подход

object ServiceState extends Enum { 
    sealed trait EnumVal extends Value with Serializable 
    val ERROR = new EnumVal { val name = "error" } 
    val OK = new EnumVal { val name = "ok" } 
} 

ScalaEnum

что приятно об этом, что вы можете использовать этот шаблон

object EnumImplicits { 
    /** 
    * Produce a JSON formatter for the Enum type 
    * 
    * e.g. implicit val interactionLineReasonFormat = enumFormat(InteractionLineReason) 
* 
* @param ev The enclosing enum "object" to provide a formatter for that extends Enum 
* @tparam A Implied from "ev" 
* @return A JSON reader and writer format 
*/ 
def enumFormat[A <: Enum](ev: A): Format[A#EnumVal] = 
new Format[A#EnumVal] { 
    override def reads(json: JsValue): JsResult[A#EnumVal] = { 
    json match { 
     case JsString(s) => 
     ev.values.find(_.name == s).map(JsSuccess(_)).getOrElse(JsError(s"$s is not a valid InteractionType")) 
     case _ => 
     JsError(s"${json.toString()} is not a valid InteractionType") 
    } 
    } 
    override def writes(o: A#EnumVal): JsValue = JsString(o.toString()) 
} 
} 
2

Basic enumerations в Scala неуклюж:

  1. Если вы хотите использовать их в сопоставлении с образцом, вы будете не видеть следующее предупреждение компилятором «матч не может быть исчерпывающим», и вы можете неожиданно столкнуться с scala.MatchError в рунете IME.
  2. Они не совместимы с перечислением Java - это не очень страшно, если вы не поддерживаете API для Java, но если вы это сделаете, это может стать неожиданным разочарованием для вас.
  3. Перегрузка с перечислениями Scala, не работающими в связи с фактом того же типа перечислений после стирания. Таким образом, следующий код снимок не является действительным:

    object WeekDays extends Enumeration { 
        val Mon, Tue, Wed, Thu, Fri = Value 
    } 
    
    object WeekEnds extends Enumeration { 
        val Sat, Sun = Value 
    } 
    
    object DaysOperations { 
        def f(x: WeekEnds.Value) = "That's a weekend" 
        def f(x: WeekDays.Value) = "That's a weekday" 
    } 
    

Он будет бросать error: double definition: have the same type after erasure: (x: Enumeration#Value)String. Как вы видите, scala.Enumeration не является удобным и предпочитает не использовать его, это сделает вашу жизнь проще.

Правильные подходы: Правильный подход использует комбинацию case object или object с sealed класса:

object WeekDays { 
    sealed trait EnumVal 
    case object Mon extends EnumVal 
    case object Tue extends EnumVal 
    case object Wed extends EnumVal 
    case object Thu extends EnumVal 
    case object Fri extends EnumVal 
    val daysOfWeek = Seq(Mon, Tue, Wed, Thu, Fri) 
} 

Кроме того, вы можете не использовать wrapper object для перечисления:

sealed trait Day { def description: String } 
case object Monday extends Day { val description = "monday is awful" } 

Использование сторонней библиотеки - Enumeratum также может решить проблему scala.enumeration, это безопасная и мощная реализация перечислений, простая в использовании и понятная.

libraryDependencies ++= Seq(
    "com.beachape" %% "enumeratum" % enumeratumVersion 
    ) 

    import enumeratum._ 

    sealed trait Day extends EnumEntry 

    object Greeting extends Enum[Greeting] { 
     val values = findValues 

     case object Mon  extends Day 
     case object Tue  extends Day 
     case object Wed  extends Day 
     case object Thu  extends Day 
     case object Fri  extends Day 
    } 
Смежные вопросы