【问题标题】:Scala: Using companion object's parent's protected methodsScala:使用伴随对象的父对象的受保护方法
【发布时间】:2012-09-06 00:42:39
【问题描述】:

我有一组在类层次结构中管理数据库存储的类,如下所述,并且希望案例类能够访问伴随对象的父类中的受保护方法:

class TableBase[T] { 
  protected def insert(...):T {...}
  protected def update(...) {...}
  // Other "raw" CRUD-methods that I don't want the 
  // world to have access to
}

object User extends TableBase[User] { 
}

case class User(id:Int, email:String) { 
  // But here it would be really useful to access the "raw" CRUD methods:
  def changeEmail(newEmail:String) = User.update(...)
}

唯一的问题是 User.changeEmail 中对 User.update 的调用是非法的,因为 User(类)不在 TableBase 的继承链中:

method update in class TableBase cannot be accessed in object models.User 
Access to protected method update not permitted because enclosing class 
class User in package models is not a subclass of class TableBase in package 
models where target is defined

是否有(方便的)方法来允许这种类型的调用?

现在我必须要么将 changeEmail 类型的函数移动到单例中,这使得调用代码相当冗长,要么复制方法签名。

【问题讨论】:

  • 声明方法private or protected at the package-level是一个选项吗?
  • 理论上是的。这需要相当多的重新调整 - TableBase 位于一个单独的符号链接源共享项目中,被其他几个项目使用,因此破坏包空间将是一团糟。

标签: scala


【解决方案1】:

我刚刚意识到一个可能的解决方案是将 User 和 TableBase 之间的“is-a”切换为“has-a”关系,如下所示:

class TableBase[T] { 
  def insert(...):T {...}
  def update(...) {...}
}

object User { 
  private val db = new TableBase[User]
}

case class User(id:Int, email:String) { 
  def changeEmail(newEmail:String) = User.db.update(...)
}

我希望能够在 User 中自定义 TableBase 的某些方面,但这实际上仍然是可能的,而且非常简单:

object User { 
  private val db = new TableBase[User] { 
    // Override stuff here
  }
}

实际上,这比我最初拥有的解决方案要好得多,并且避免了方法上的命名冲突(即,有理由在 User 上公开“插入”,最好不要让它导致部分受保护的重载)。

【讨论】:

  • 我尝试了这个,但对结果不满意 - 最后,哪些功能将进入 TableBase(因此被隐藏)以及哪些功能可以从外部访问,这有点武断。最后只是让 TableBase 内容公开。在更明确的情况下,这是我会采取的方法。
【解决方案2】:

您可以将接口作为特征 CrudOps[T] 提供,让另一个 protected 特征 TableBase[T] 从它派生并提供实现,并从 TableBase[T] 派生单例对象。这样 TableBase 在编译单元之外是不可见的,但客户端可以安全地使用 CrudOps[T]。

【讨论】:

  • 我可能遗漏了一些东西——我希望 TableBase/CrudOps 中的方法只能在 User 类和单例中调用,而不是在外部调用——如果客户端可以“使用”CrudOps,然后更新/插入/等是外部可调用的? (注意这些文件实际上不在同一个包或源文件中)
  • 啊,我明白了,这让事情变得更容易了——只需让 TableBase trait 受包保护。例如,如果你的包是 com.example.crud,你需要声明 protected[crud] TableBase[T]...
  • 请参阅我的comment,了解有关保护 TableBase 包的问题。
猜你喜欢
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 2012-11-22
  • 2018-02-06
  • 2011-08-21
  • 1970-01-01
  • 1970-01-01
  • 2019-10-06
相关资源
最近更新 更多