Scala:从子类动态访问伴随对象

Scala:从子类动态访问伴随对象,scala,Scala,我想要两个带有伴生对象的类,以便在我没有实例时从类实例以及伴生对象访问共享值 最后,我想解析一个字符串并创建匹配类的实例,反过来,从实例创建一个字符串 以下代码可以工作,但似乎过于复杂: abstract class Person(val age: Int = 0) { val pronoun: String override def toString = pronoun + " is " + age + " years old" } class Man(override va

我想要两个带有伴生对象的类,以便在我没有实例时从类实例以及伴生对象访问共享值

最后,我想解析一个字符串并创建匹配类的实例,反过来,从实例创建一个字符串

以下代码可以工作,但似乎过于复杂:

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
因此,为了实现这一点,我为每个子类创建了一个类和一个同伴对象,并手动引用同伴对象中的
代词
(例如
val-degen=Man.degen

旁注:在抽象类中设置默认值
age=0
,会让事情变得更简单,但这似乎不对


我尝试过使用特质等,但都没有成功。有没有更好的方法可以用更少的重复代码来实现这一点?

您必须遵循哪些约束条件?例如,你必须能够调用人代词吗?因为一个选项是简单地在
Person
对象中创建
mandeon
womandeon
字段,并删除
Man
Woman
同伴对象。另外,0默认年龄值有什么意义?您只需将年龄传递给
个人

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

如果必须在
Man
Woman
对象中包含代词字段,那么必须在
Man
Woman
对象中包含代词字段:

您必须遵循哪些约束条件?例如,你必须能够调用人代词吗?因为一个选项是简单地在
Person
对象中创建
mandeon
womandeon
字段,并删除
Man
Woman
同伴对象。另外,0默认年龄值有什么意义?您只需将年龄传递给
个人

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

如果必须在
Man
Woman
对象中包含代词字段,那么必须在
Man
Woman
对象中包含代词字段:

考虑到这个问题,我会通过以下方式简化它:

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秒钟才明白你在做什么,而可读性在这些日子里非常重要


希望这对你有帮助。问候

考虑到这个问题,我会通过以下方式简化它:

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秒钟才明白你在做什么,而可读性在这些日子里非常重要


希望这对你有帮助。问候

没错,我上面的例子是一个简化。我想我的问题是,我没有考虑把“代词”放在宾语中。其次,我不知道我确实可以在这里使用trait而不是抽象类。虽然与第二个答案非常相似,但我会选择这一个作为正确答案,因为我发现这里的特质解决方案稍微干净一些。谢谢没错,我上面的例子是一个简化。我想我的问题是,我没有考虑把“代词”放在宾语中。其次,我不知道我确实可以在这里使用trait而不是抽象类。虽然与第二个答案非常相似,但我会选择这一个作为正确答案,因为我发现这里的特质解决方案稍微干净一些。谢谢也非常感谢您的解决方案!我将默认值设置为0,因为每个扩展了
Person
的类都有相应的对象,这些类需要一个
age
参数。我没有选择这个作为“正确”答案的唯一原因是,对于trait解决方案,我不必带着
age
参数。这可能会对其他要求很方便,所以也谢谢你的回答。哈,没问题,我不在乎被选为“正确”,而是关心帮助。我把它作为一个抽象类留下,只是因为你是这样做的:)我也更喜欢traits。如果你没有特别的理由使用抽象类,那么就倾向于traits。当你开始把它们堆放在一起时,它们会很有趣。也非常感谢你的解决方案!我将默认值设置为0,因为每个扩展了
Person
的类都有相应的对象,这些类需要一个
age
参数。我没有选择这个作为“正确”答案的唯一原因是,对于trait解决方案,我不必带着
age
参数。这可能会对其他要求很方便,所以也谢谢你的回答。哈,没问题,我不在乎被选为“正确”,而是关心帮助。我把它作为一个抽象类留下,只是因为你是这样做的:)我也更喜欢traits。如果你没有特别的理由使用抽象类,那么就倾向于traits。当你开始把它们堆放在一起时,它们会很有趣。