Ссылка на абстрактный тип вне признака для построения класса - PullRequest
0 голосов
/ 05 июля 2018

Предпосылка:

Я хочу отделить информацию, необходимую для создания экземпляра класса, от информации, необходимой для "запуска" класса. Однако информация, необходимая для «запуска» класса, может отличаться от класса к классу. Таким образом, я представляю, что у класса «есть» конкретная информация для его запуска, и оба они идут вместе.

Вот пример моего кода:

trait Machine {
  type Params <: BaseParams

  def start(machineParams: Params): Unit
}

trait BaseParams {
  def speed: Int
  def power: Int
}

class FlyingMachine() extends Machine {
  type Params = FlyingParams

  override def start(machineParams: Params): Unit = {
    println(s"I'm flying with $machineParams")
  }
}

trait FlyingParams extends BaseParams {
  def height: Int
}


abstract class MachineOwner{

  val machine: Machine

  def params: machine.Params

  def startMachine(): Unit = {
    machine.start(params)
  }
}

Это компилирует, проходит тесты, я счастлив.

Проблема: я использую val machine: Machine для определения def params: machine.Params. Мне сказали сделать это def, чтобы дать разработчику больше свободы. Если я это сделаю, я больше не могу ссылаться на machine.Params

На данный момент я не знаю, как продолжить. Я продолжаю думать, что если это будет def и определенно не val, то моя архитектура неверна.

So

  1. Является ли мой подход к этой проблеме неправильным, учитывая предпосылку, с которой я изложил?
  2. Если это не так, есть ли способ достичь этого, используя def вместо val в классе MachineOwner?

EDIT Учитывая ответ Алексея Романова, последний бит кода будет выглядеть так

abstract class MachineOwner{

  type Params1 <: BaseParams

  def machine: Machine { type Params = Params1 }

  def params: Params1

  def startMachine(): Unit = {
    machine.start(params)
  }
}

class FlyingMachineOwner(
  machine: FlyingMachine
) extends MachineOwner {

  override type Params1 = FlyingParams

  override def params = FlyingParams(1,1,1)
}

Но это не компилируется, потому что ожидает переопределение специально для def machine: Machine { type Params = Params1 }. Как это определить?

1 Ответ

0 голосов
/ 05 июля 2018

На это действительно невозможно ответить, не зная желаемой семантики.

Если MachineOwner должен владеть одной машиной, то «сделать это определением, чтобы у разработчика была больше свободы», - плохой совет: свобода, которую он дает, заключается в точном возврате разных машин из разных вызовов на def machine и не хранить ссылки на машины, которые он выдает.

Если предполагается наличие нескольких машин, должны ли все они иметь одинаковый тип Params? Тогда вы бы сделали что-то вроде

abstract class MachineOwner{

  type Params1 <: BaseParams

  def machine: Machine { type Params = Params1 }

  def params: Params1

  def startMachine(): Unit = {
    machine.start(params)
  }
}

Или, если нет, то вам снова нужен другой дизайн, может быть def params(machine: Machine): machine.Params. И т. Д.

Для редактирования: вы можете сделать

class FlyingMachineOwner(
  _machine: FlyingMachine
) extends MachineOwner {

  override type Params1 = FlyingParams

  override def params = FlyingParams(1,1,1)

  override def machine = _machine
}

но это действительно кажется излишне сложным по сравнению с тем, что вы получаете с параметрами типа.

...