【问题标题】:Simple Scala getter/setter override简单的 Scala getter/setter 覆盖
【发布时间】:2012-12-28 12:18:56
【问题描述】:

假设我们有一个具有“名称”属性的类:

class SuperFoo(var name: String) 

如果我想覆盖它,例如在调用周围添加一些锁定:

class SubFoo(n: String) extends SuperFoo(n) {
  val lock = new ReentrantLock
  override def name(): String =
    {
      lock.lock
      try {
        super.name
      } finally {
        lock.unlock
      }
    }
  override def name_=(arg: String): Unit = {
    lock.lock
    try {
      super.name = arg
    } finally {
      lock.unlock
    }
  }
}

以上产生编译错误:

super may be not be used on variable name 

任何想法如何正确实现这一点? (即覆盖 getter 和 setter 以在它们周围添加锁定)。谢谢!

【问题讨论】:

  • 编译器似乎认为我正在覆盖一个变量:如果我从 getter 中删除 super.name 语句,我会收到以下错误消息:“覆盖 String 类型的 SuperFoo 类中的变量名;方法名称不能覆盖可变的"

标签: scala inheritance properties setter getter


【解决方案1】:

这里需要直接引用超类的setter/getter。通常你应该这样写:

class SubFoo(n: String) extends SuperFoo(n) {
  val lock = new ReentrantLock
  override def name(): String =
    {
      lock.lock
      try {
        super.name()
      } finally {
        lock.unlock
      }
    }
  override def name_=(arg: String): Unit = {
    lock.lock
    try {
      super.name_=(arg)
    } finally {
      lock.unlock
    }
  }
}

但是,如果 setter 编译时没有任何问题,getter 则不会,因为编译器会将其视为super.name.apply()(字符串可以通过隐式转换获得此方法)。

我看到了几个选项:

  1. 优先组合优于继承(经典)。
  2. 更改变量名,将其设为私有并在超类中写入访问器(见下文)。
  3. 求助于反射/手动名称 umanling voodoo。

我会选择选项 #1,但这里是选项 #2 的代码:

class SuperFoo( private var nameVar: String) {
  def name: String = nameVar
  def name_=(arg: String): Unit = nameVar = arg
}

class SubFoo(n: String) extends SuperFoo(n) {
  val lock = new ReentrantLock
  override def name(): String =
    {
      lock.lock
      try {
    super.name
      } finally {
        lock.unlock
      }
    }
  override def name_=(arg: String): Unit = {
    lock.lock
    try {
      super.name = arg
    } finally {
      lock.unlock
    }
  }
}

编辑:这是选项 #1 的可行实现:

trait Foo {
  def name: String
  def name_=(arg: String): Unit
}

class SimpleFoo( var name: String) extends Foo

class LockedFoo(foo: Foo) extends Foo {
  val lock = new ReentrantLock
  def name(): String =
    {
      lock.lock
      try {
        foo.name
      } finally {
        lock.unlock
      }
    }
  def name_=(arg: String): Unit = {
    lock.lock
    try {
      foo.name = arg
    } finally {
      lock.unlock
    }
  }
}

【讨论】:

  • 谢谢-我试图避免选项2并以某种方式使用您的选项1(由于反射,选项3是不可能的)。但是,即使属性不是字符串,选项 1 也无法编译,请尝试使用 Int,您会明白我的意思。 Scalac 认为您出于某种原因试图覆盖“名称”字段...任何想法如何让选项 1 与例如 Int 一起工作?
  • 我添加了选项 1 解决方案。遵循 GoF 指南,装饰器设计模式允许向现有实现添加行为。
猜你喜欢
  • 2011-03-11
  • 2018-11-08
  • 2014-11-12
  • 2013-08-09
  • 2015-05-11
  • 1970-01-01
相关资源
最近更新 更多