gpt4 book ai didi

scala - 用Scala中的另一个特征继承自类型特征

转载 作者:行者123 更新时间:2023-12-04 18:04:59 25 4
gpt4 key购买 nike

我正在尝试为我的应用程序设计一个小型模块系统,以便我可以这样做:

new MyApplication extends Module1 with Module2 ... with ModuleN

为了让我的模块在应用程序中注册自己,我还有:
trait ModuleRegistry {
def register(start: () => Unit) = // Stores start functions in a list
}

trait Module {
self: ModuleRegistry =>
self.register(start)
def start(): Unit
}

class Application extends ModuleRegistry {
}

trait Module1 extends Module {
...
}

这个想法是模块可以在注册表中注册一个函数,以便在应用程序启动时调用。不幸的是,Scala 编译器强制我这样做:
trait Module1 extends Module {
self: ModuleRegistry =>
}

这意味着模块的所有实现都必须使用注册表显式地自我键入自己,而理想情况下他们对此一无所知。

所以我的问题是:
  • 为什么编译器强制我在扩展特征上重新指定这种自我类型?理想情况下,我什至不希望扩展特征“看到”这种类型,因为它应该由基本 Module 特征处理。 “具体”模块是由第 3 方实现的,因此向他们公开注册表似乎有点难看。
  • 有没有更好的方法来做我想要在 Scala 中实现的目标,以便可以自由混合模块?
  • 最佳答案

    这不是蛋糕模式的好用法,因为您希望所有模块都保留自己的功能(大概),而不是在混合时相互混合和覆盖。如果您想要后者,您不应该:仅使用非常仔细的设计可以提供可预测和合理的结果,如果第三方应该提供模块,那么几乎可以保证设计不会那么仔细。

    相反,您应该遵守“优先组合优于继承”的建议。

    trait Module {
    def start: Unit
    }

    trait Modular {
    protected def moduleList: Seq[Module]
    protected def register() = moduleList.map(m => m.start _)
    }

    class Application(modules: Module*) extends Modular {
    protected def moduleList: Seq[Module] = modules // Fix varargs type
    protected val registered = register()
    }

    object Module1 extends Module {
    def start = println("One")
    }

    object Module2 extends Module {
    def start = println("Two")
    }

    val app = new Application(Module1, Module2) {
    registered.foreach(_())
    }
    // Prints "One", then "Two"

    这是假设一个模块可以使用单例。如果你需要一个特定的实例,你可以覆盖伴随对象中的 apply (语法是 Module1()),或者添加一个 Module1 扩展的构建器特征(例如 trait ModuleBuilder { def module: Module } )。

    关于scala - 用Scala中的另一个特征继承自类型特征,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31506027/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com