2016-02-03 29 views
0

我想與同伴幾個類,以便從一個類的實例,以及從同伴對象訪問共享值的對象,當我沒有一個實例對象。斯卡拉:動態訪問同伴從子類

最後我想解析字符串和圓創建匹配的類的實例,也是另一種方式,創建從實例的字符串。

下面的代碼工作,但似乎過於複雜:

abstract class Person(val age: Int = 0) { 
    val pronoun: String 
    override def toString = pronoun + " is " + age + " years old" 
} 

class Man(override val age: Int) extends Person { 
    val pronoun = Man.pronoun 
} 

class Woman(override val age: Int) extends Person { 
    val pronoun = Woman.pronoun 
} 

object Man extends Person { 
    val pronoun = "he" 
} 

object Woman extends Person { 
    val pronoun = "she" 
} 

object Person { 
    def fromString(pronoun: String, age: Int): Option[Person] = { 
     pronoun match { 
      case Man.pronoun => Some(new Man(age)) 
      case Woman.pronoun => Some(new Woman(age)) 
      case _ => None 
     } 
    } 
} 

// Man.pronoun 
// -> should return "he" 

// Woman.pronoun 
// -> should return "she" 

// new Man(30).toString 
// -> should return "he is 30 years old" 

// Person.fromString("she", 20) 
// -> should return a Some(Woman) with age = 20 

所以,對於這個工作,我爲每個子類的類和同伴對象和手動引用來自同伴對象pronoun(例如val pronoun = Man.pronoun)。

邊注:在抽象類設置的默認值age = 0使事情進一步下跌更容易一點,但它似乎沒有吧?

我使用特點等,但都沒有成功嘗試。有沒有更好的方式來實現這個重複性較低的代碼?

回答

1

鑑於這個問題,我會做它簡化:

case class Person(pronoun: String, age: Int) { 
    override def toString = s"$pronoun is $age years old" 
} 

,並應解決這個問題,但我猜你提出的問題是一個比較複雜的一個的簡化,所以我的解決方案成爲:

trait Person { 
    protected def age: Int 
    protected def pronoun: String 
    override def toString = s"$pronoun is $age years old" 
} 

case class Man(override val age: Int) extends Person { 
    override protected def pronoun: String = Person.SHE 
} 
case class Woman(override val age: Int) extends Person { 
    override protected def pronoun: String = Person.HE 
} 

object Person { 

    val HE = "he" 
    val SHE = "she" 

    def parse(pronoun: String, age: Int): Option[Person] = { 
    pronoun match { 
     case HE => Some(Man(age)) 
     case SHE => Some(Woman(age)) 
     case _ => throw new IllegalArgumentException(s"pronoun $pronoun was not recognized") 
    } 
    } 

} 

這對我來說看起來並不糟糕,解決了這個問題並且非常可讀。說了這麼多,你的代碼看起來不錯(默認是0)。這看起來很複雜,但我花了2秒才明白自己在做什麼,而且可讀性近來非常重要。

希望這會幫助你。問候!

+0

這是正確的,我上面的例子是一個簡化。我想我的問題是,我沒有考慮將「代詞」放在對象中。其次,我不知道我確實可以在這裏使用一個特質,而不是抽象類。雖然與第二個答案非常相似,但我會選擇這一個爲正確的,因爲我發現特質解決方案在這裏略顯清晰。謝謝! – Nick

1

什麼是你必須遵守的約束?例如。你必須能夠調用Man.pronoun?因爲一個選擇是簡單地創建在Person對象ManPronounWomanPronoun領域和刪除ManWoman同伴對象。另外,什麼是0默認年齡值的點?您可以簡單地將年齡傳遞給Person

abstract class Person(val age: Int) { 
    val pronoun: String 
    override def toString = pronoun + " is " + age + " years old" 
} 

class Man(override val age: Int) extends Person(age) { 
    val pronoun = Person.ManPronoun 
} 

class Woman(override val age: Int) extends Person(age) { 
    val pronoun = Person.WomanPronoun 
} 

object Person { 

    val ManPronoun = "he" 
    val WomanPronoun = "she" 

    def fromString(pronoun: String, age: Int): Option[Person] = { 
    pronoun match { 
     case ManPronoun => Some(new Man(age)) 
     case WomanPronoun => Some(new Woman(age)) 
     case _   => None 
    } 
    } 
} 

如果你必須有內部ManWoman對象的代名詞場,好,那你必須有ManWoman對象。 :)

+0

非常感謝您的解決方案!我設置了默認值0,因爲每個擴展需要'age'參數的Person類的類都有伴隨對象。我沒有選擇這個作爲「正確」答案的唯一原因是因爲利用特質解決方案,我不必揹負「年齡」的說法。它可能會與其他要求一起使用,所以謝謝你的回答。 – Nick

+0

哈,沒問題,我不在乎被選爲「正確」,而是在於幫助。我把它作爲一個抽象類,只是因爲你有這種方式:)我更喜歡特質。如果你沒有特殊的理由來使用抽象類,那就傾向於特質。當你開始堆疊它們時,它們非常有趣。 – slouc