在 Scala 中有一种方法可以在 main 中创建所有实例。
例如,我有以下类:作者、页面、书籍。我主要创建这三个类的实例。在 Book 的一个实例中,我放置了作者和页面。
然后我想检查是否有不属于任何书的页面。
这个例子只是解释性的,你不要太重视它们。
谢谢你们。抱歉英文翻译不好。
在 Scala 中有一种方法可以在 main 中创建所有实例。
例如,我有以下类:作者、页面、书籍。我主要创建这三个类的实例。在 Book 的一个实例中,我放置了作者和页面。
然后我想检查是否有不属于任何书的页面。
这个例子只是解释性的,你不要太重视它们。
谢谢你们。抱歉英文翻译不好。
简短的回答:不,没有完全自动化的方法可以做到这一点。您需要遍历所有分配的对象,这是垃圾收集器可以做的事情,但程序本身不能。
以下是跟踪哪些子对象已附加到根对象的一种可能方法的草图。
定义允许我们区分子对象和根对象的基本特征:
trait Root
trait Sub {
def register(r: Root)
def deregister(r: Root)
def isRegistered: Boolean
}
Book
然后我们定义一个可以添加页面的根对象:
class Book(val title: String) extends Root {
private var pages: Set[Page] = Set()
Books.books += this
def add(p: Page) {
pages += p
p.register(this)
}
def remove(p: Page) {
pages -= p
p.deregister(this)
}
}
在实例化时,每本书都将自己添加到一个全局存储库中:
object Books {
var books: Set[Book] = Set()
}
同样对于子对象Page
:
class Page(number: Int) extends Sub {
private var owner: Option[Root] = None
Pages.pages += this
def register(r: Root) = owner match {
case None =>
owner = Some(r)
case Some(o) =>
sys.error("%s is already owned by %s, thus it cannot be owned by %s"
.format(this, o, r))
}
def deregister(r: Root) = owner match {
case Some(s) if r == s =>
owner = None
case Some(s) =>
sys.error("%s is owned by %s, but not by %s"
.format(this, s, r))
case None =>
sys.error("%s is not owned at all, thus also not by %s"
.format(this, r))
}
def isRegistered = owner.nonEmpty
}
object Pages {
var pages: Set[Page] = Set()
def allRegistered = pages.forall(_.isRegistered)
}
一些使用示例:
val p1 = new Page(1)
val p2 = new Page(2)
val p3 = new Page(3)
val b1 = new Book("Fahrenheit 451")
val b2 = new Book("Brave New World")
b1.add(p1)
b1.add(p2)
b2.add(p3)
println(Pages.allRegistered) // true
val p4 = new Page(4)
println(Pages.allRegistered) // false
b2.add(p4)
b2.remove(p3)
println(Pages.allRegistered) // false
b2.add(p1) // Exception: already owned
注意:要记住的设计决策,开放式问题:
如果要销毁子对象,如何进行?从全局存储库中删除它?
一个子对象可以被多个根对象拥有吗?
拥有多个非全局存储库会更好吗?这可能意味着我们需要工厂来创建和注册子对象。
在并发设置中,我们必须同步对(全局)存储库的访问
我们可以将用于(取消)注册子对象的代码移动到单个特征中,然后在每个根对象中重用它吗?
注二:如果我们有反向指针,我们只需要一个(全局)子对象存储库。但是,我不知道任何提供内置反向指针的语言。
不,您必须自己跟踪它们。不要认为任何语言真的可以做到这一点。当然,你可以编写你的类,让它们这样做,但这是你的责任。
你可以
// If you use the REPL, :paste both class and object together
class Page {
Page.everything += this
var booked: Option[Book] = None // Or just set to null
}
object Page {
val everything: collection.mutable.HashSet[Page] = collection.mutable.HashSet()
}
class Book {
var pages: Vector[Page] = Vector()
def addPage(p: Page) { p.booked = Some(this); pages = pages :+ p }
}
// Create all your books and pages and assign them all
Page.everything.filter(_.booked.isEmpty) // This contains all unassigned pages
跟踪自己。(这是假设单线程代码;以您的专业水平,可能不值得担心如何并行执行此操作。)
或者,如果您想确保main
方法中的所有事情都发生,您可以执行类似的操作
// File Page.scala
class Page(text: String)(implicit mhm: MustHaveMe) {
}
// File Main.scala
object Main {
sealed trait MustHaveMe
private final object YesYouHaveMe extends MustHaveMe
def main(args: Array[String]) {
implicit val okayHere = YesYouHaveMe
new Page("Once upon a time")
}
}
现在,访问限制将阻止任何人Main.scala
创建新页面,并且只有文件中的main
方法Main.scala
具有创建Page
. 因此,您可以更轻松地避免在其他地方创建对象。
我必须能够独立创建我的页面和书籍 我感兴趣的事情是跟踪创建的所有实例。正如你所建议的,我想我也部署了我的课本:
class Book(var name: String, var pages: List[Page]){
AllBook.allbook += this
}
object AllBook {
var allbook: Set[Book] = Set()
}
以类似的方式还有 Page 类。作为 main 方法中的最后一条指令,使用必须控制我的约束的方法调用“验证”。
这可能没问题?有更好的解决方案吗?
注意:约束是独立的,尊重类的实现
请原谅我的英文翻译不好