2016-03-03 20 views
8

Tôi đang cố gắng mô phỏng hành vi enum bằng cách sử dụng đối tượng trường hợp. Nó cảm thấy một chút tiết, và không thanh lịch, và tôi đã tự hỏi nếu có một cách tốt hơn để đạt được điều này.Cách thanh lịch để thực hiện enum sử dụng đối tượng trường hợp

Vì vậy, đây là một ví dụ:

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

Có cách nào tốt hơn để có được bản đồ ngược này từ một chuỗi các đối tượng trường hợp thực tế? Hoặc nói chung thực hiện tốt hơn điều này?

Trả lời

10

Tôi thích cách tiếp cận như vậy:

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

để có được một giá trị:

ProgressStatus.IN_PROGRESS.value 

để có được tất cả các giá trị:

+1

Cảm ơn! Nhưng đây là basiclly cùng một mã như tôi đã viết .. Trong ví dụ của bạn vẫn không có cách nào để ánh xạ một chuỗi để đối tượng trường hợp coresponding. – Tomer

+0

Ví dụ: '' 'ProgressStatus (" CHẤP NHẬN ")' '' khớp '' 'ProgressStatus.ACCEPTED''' –

+0

Cách tiếp cận tốt đẹp !!! – Dani

-2

tôi thích một cách tiếp cận như vậy

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

những gì tốt đẹp về việc này là bạn có thể sử dụng mẫu này

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 trong Scala là vụng về:

  1. Nếu bạn muốn sử dụng chúng trong mô hình khớp, bạn sẽ không thấy cảnh báo tiếp theo bởi trình biên dịch "đối sánh có thể không đầy đủ" và bạn có thể gặp phải bất ngờ với scala.MatchError trong runt ime.
  2. Chúng không tương thích với enum của Java - nó không phải là rất đáng sợ nếu bạn không hỗ trợ API cho Java, nhưng nếu bạn làm điều đó, nó có thể là một sự thất vọng bất ngờ cho bạn.
  3. Quá tải với các điều tra của Scala không hoạt động do thực tế cùng một loại liệt kê sau khi xóa. Vì vậy, các ảnh chụp mã tiếp theo là không hợp lệ:

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

Nó sẽ ném error: double definition: have the same type after erasure: (x: Enumeration#Value)String. Như bạn thấy, scala.Enumeration không thân thiện với người dùng và không thích sử dụng nó, nó sẽ làm cho cuộc sống của bạn dễ dàng hơn.

phương pháp tiếp cận bên phải: Cách tiếp cận ngay được bằng cách sử dụng sự kết hợp của case object hoặc object với sealed lớp:

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

Ngoài ra, bạn có thể không sử dụng wrapper object cho enum:

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

Tận dụng thư viện của bên thứ ba - Enumeratum cũng có thể giải quyết vấn đề của scala.enumeration, đây là kiểu triển khai liệt kê loại an toàn và mạnh mẽ, dễ sử dụng và dễ hiểu.

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 
    } 
Các vấn đề liên quan