创建一个扩展抽象类的对象并将其添加到 Scala 中类型抽象类的序列中

Posted

技术标签:

【中文标题】创建一个扩展抽象类的对象并将其添加到 Scala 中类型抽象类的序列中【英文标题】:Creating an object extending an abstract class and adding it to a sequence of the type abstract class in Scala 【发布时间】:2022-01-15 05:16:39 【问题描述】:

所以我有一个抽象类和一堆扩展它的对象:

abstract class Command(val str: String, val help: String):
   def apply(args: Seq[String]): String

object Command:
   var all: Seq[Command] = Seq(Help, Quit, Play, Def)

   def apply(args: Seq[String]): String = 
     //Do some stuff

object Help extends Command("?", "print help"):
   def apply(args: Seq[String]): String = 
     //Do some stuff

object Quit extends Command(":q", "quit this app"):
   def apply(args: Seq[String]): String = 
     //Do some stuff

object Play extends Command("!", "play chord"):
   def apply(args: Seq[String]): String = 
     //Do some stuff

object Def extends Command("def", "define function"):
   def apply(args: Seq[String]): String = 
     case Seq(_, "!", _*) => 
      val name = args.head
      val func = args.tail  
      
      Command.all :+ Command(s"$name", func) 

      s"defined $name: $func"
    case _ => ""


正如您所见,不同的对象扩展了抽象类,对象 Def 是一个文本命令,您首先输入 def 进行定义,然后 apply 中的字符串 seq 将成为命令本身。正如您在 Def 中看到的,我尝试将此新命令添加到 Command-obj 中的命令序列中。但它不起作用,我无法创建val cmd = new Command(s"$name", s"Execute $name") 然后从那里开始工作。目的是让用户定义自己的命令,因为其他命令是作为扩展抽象的对象创建的,我真的不知道如何到达那里。有什么建议吗?

【问题讨论】:

为每个命令添加新类型感觉几乎没有意义。也许更好的方法是简单地将Command 创建为一个案例类和代表您预定义“命令”的案例类的一堆值。 也许是这样,但这是我得到的,而另一个人想要这样,我还能这样做吗? 我可能会创建一个用户可以输入的带有空 str 参数的类型,但是每次都会覆盖该命令,例如我希望用户输入?并获取命令列表 ?、:q、!、def 以及它们自己定义的命令。 【参考方案1】:

不确定它是否是您所指的,但这无济于事,因为结果被丢弃了。

Command.all :+ Command(s"$name", func)

你可能是说

Command.all = Command.all :+ Command(s"$name", func)

【讨论】:

这确实有帮助,但我的问题正是要添加到 Seq 中,现在解决了。【参考方案2】:

想出了一个解决方案: 创建一个新类,当他们从Def 类输入name 时将调用该类。如果他们想定义一个在钢琴上演奏 E 小调和弦的函数,他们会写:def Em ! p 64 67 71 所以我 Def 现在是 name = Emfunc = Seq("!", "p", "64", "71") 然后我们创建一个 DefinedDefined @ 的新实例987654329@ 然后我们将这个实例(Command(抽象类)类型)添加到命令对象序列var all: Seq[Command] = Seq(Help, Quit, Play, Def, Em) 现在当他们输入命令“Em”时,它将调用Play 的应用函数func = Seq("!", "p", "64", "71")在 Play 自己的 apply 函数中。这里一个明显的缺陷是 Defined 的 apply 不需要 args: Seq[String] 但由于 Command 类型的所有其他 Object 都需要一个序列才能在调用命令时提供数据,所以我不知道如何避免它.

class Defined extends Command(s"$Def.name", s"Execute the function $Def.name")
      //New function every new instance
      val command = Def.func.tail
        def apply(args: Seq[String]): String =
          Play(command) 

基于他们在 Def 命令中输入的新类:

object Def extends Command("def", "Define function"):
  var name = ""
  var func = Seq("")
  def apply(args: Seq[String]): String = args match
    case Seq(_, "!", _*) => 
      name = args.head //Ex. Em
      func = args.tail //Ex. ! p 64 67 71

      Command.cmdSet.add(new Defined)

      s"defined $name: $func.mkString(" ")"
    case _ => ""
  def getName: String = name
  def getFunc: Seq[String] = func

正如蒂姆指出的那样,如果我不更改 Command 中的 var all 会更好,所以我将其修改为:

class CommandSet:
  private var commandSet: Seq[Command] = Seq(Help, Quit, Play, Def)
  
  def add(command: Command): Unit =
    commandSet = commandSet :+ command

  def get: Seq[Command] =
    commandSet
     


object Command:
  val cmdSet = new CommandSet
  def all: Seq[Command] = cmdSet.get

创建了一个用于保存命令序列的类。所以现在在Def 我访问val cmdSet: commandSet 并使用add 函数然后在object Command 而不是命令序列是一个var 现在def all: Seq[String] = cmdSet.get 返回类CommandSet 中的私有序列

【讨论】:

让类修改其他类中的vars 确实不是一个好的设计。与其在Command 中使用var,不如使用包含活动命令列表的单独CommandSet 类。然后Def 可以创建一个新的Command,并且可以将其添加到CommandSet 以创建一个新的CommandSet,避免所有使用var 感谢您的提示!更新了我的答案。更好?

以上是关于创建一个扩展抽象类的对象并将其添加到 Scala 中类型抽象类的序列中的主要内容,如果未能解决你的问题,请参考以下文章

android 从扩展 AsyncTask 创建一个对象并将其发送到另一个活动

Scala 中的特征和抽象方法覆盖

Scala 面向接口编程

Scala的密封抽象与抽象类

Scala基础之抽象

Scala基础之抽象