Вопрос по setter, properties, scala, inheritance, getter – Простое переопределение метода получения / установки Scala

9

Допустим, у нас есть класс со свойством name:

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 

Есть идеи, как правильно это реализовать? (т.е. переопределить метод получения и установки, чтобы добавить блокировку вокруг них). Спасибо!

Компилятор, кажется, думает, что я переопределяю переменную: если я удаляю оператор super.name из получателя, я получаю следующее сообщение об ошибке: «переопределение имени переменной в классе SuperFoo типа String; имя метода не может переопределить изменяемый» Nikolaos

Ваш Ответ

1   ответ
6

суперкласса. Обычно вы должны написать что-то вроде:

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.name.apply() (Строки могут получить этот метод через неявные преобразования).

Я вижу несколько вариантов:

Пользу композиции над наследством (классика).Измените имя переменной, сделайте ее приватной и напишите средство доступа в суперклассе (см. Ниже).Прибегайте к размышлению / ручному названию.

Я пойду за вариант № 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
    }
  }
}
Я добавил вариант 1 решения. Следуя рекомендациям GoF, шаблон дизайна декоратора позволяет добавить поведение в существующую реализацию. paradigmatic
Спасибо. Я пытался избежать варианта 2 и каким-то образом использовать ваш вариант 1 (вариант 3 исключен из-за размышлений). Тем не менее, вариант 1 не компилируется, даже если свойство не является строкой, попробуйте с Int, и вы поймете, что я имею в виду. Скалак думает, что вы пытаетесь переопределить поле «имя» по какой-то причине ... Есть идеи, как заставить вариант 1 работать, например, с Int? Nikolaos

Похожие вопросы