Scala事件
我有一个CategoryRepository类,它实现了几个方法,可以将一个类别保存到数据库中。 我还有一个包含类别列表的对象产品。 我想做的是触发Product对象将侦听的事件,并使用其类别的新数据更新产品本身 在C语言中,我知道我可以使用委托,但我不知道在Scala中是否可以这样做 我不想让CategoryRepository类知道类Product,所以我不会调用Product中的某些方法来通过CategoryRepository更新它 我的分类报告类:Scala事件,scala,events,Scala,Events,我有一个CategoryRepository类,它实现了几个方法,可以将一个类别保存到数据库中。 我还有一个包含类别列表的对象产品。 我想做的是触发Product对象将侦听的事件,并使用其类别的新数据更新产品本身 在C语言中,我知道我可以使用委托,但我不知道在Scala中是否可以这样做 我不想让CategoryRepository类知道类Product,所以我不会调用Product中的某些方法来通过CategoryRepository更新它 我的分类报告类: trait CategoryRepo
trait CategoryRepositoryComponentImpl extends CategoryRepositoryComponent {
val categoryRepository = new categoryRepositoryImpl
class CategoryRepositoryImpl extends CategoryRepository {
val dbRepository = CategoryDbRepository
def updateAttribute(id:String, request:UpdateCategoryItem): String = {
val cat = dbRepository.get(id)
cat.update(request)
dbRepository.save(cat)
}
}
}
产品存储库看起来与此类别的存储库相同。
现在,我想在dbRepository.savecat之后添加一行,该行将触发一个事件,该事件将调用ProductRepository中的updateProduct函数
请给出一个实现示例。
谢谢。我想这或多或少就是C语言中事件和委托的实现方式。 当您定义这样的事件时,如果您想将多个参数传递给事件侦听器,那么必须使用tuples Event[Any,EventArgs]
class Event[Arg] {
type L = Arg => Unit
private val listeners = scala.collection.mutable.ListBuffer.empty[L]
def +=(listener: L) {
listeners.append(listener)
}
def apply(arg: Arg) {
listeners.foreach(_(arg))
}
}
class CategoryRepository {
val event = new Event[String]
def fireEvent(data: String) {
event(data)
}
}
object Product {
def update(data: String) {
println(s"updating: $data")
}
}
object Main extends App {
val repo = new CategoryRepository()
repo.event += Product.update
repo.fireEvent("new data")
}
基于事件的更新通道的非基本实现 我只注意概括到最基本的部分,以便为将来的进化和代码重用提供提示 基础设施 我们推出了一个更新频道
//Listens for updates to A's and notifies interested listeners
class UpdateChannel[A] {
//simplified register
var listenMap: Map[A, Listening[A]] = Map()
//update call
def apply(a: A): Unit = listenMap.get(a).foreach(_.event(a))
//update call
def registerFor(a: value, listen: Listening[A]) = listenMap += (a, listen)
}
还有一个对更正更新感兴趣的普通侦听器
//Listens to changes for type A
trait Listening[A] {
def event(upd: A): Unit
}
应用
现在我们调整Repo组件来注入通道
trait CategoryRepositoryComponentImpl extends CategoryRepositoryComponent {
val categoryRepository = new categoryRepositoryImpl
/************** NEW CODE HERE **************
* define a channel to send category updates
*******************************************/
def updateChannel: UpdateChannel[Category]
class CategoryRepositoryImpl extends CategoryRepository {
val dbRepository = CategoryDbRepository
def updateAttribute(id:String, request:UpdateCategoryItem): String = {
val cat = dbRepository.get(id)
cat.update(request)
dbRepository.save(cat)
//send the update to the channel
updateChannel(cat) //***************** << AND HERE
}
}
}
最后,我们把所有的材料放在一起
//put the pieces together
def wireup() = {
//the channel
val catChan: UpdateChannel[Category] = new UpdateChannel[Category]
//the Repository component wired to the channel
val catRep = new CategoryRepositoryComponentImpl {
val updateChannel = catChan
}
//a nice cat
val myCat: Category = ???
//a nice prod with her nice cat
val p: Product = new Product(myCat)
//prod wants to know what happens to her cat
catChan.registerFor(myCat, p)
}
评论
通过使用细化类型,我们可以使产品独立于整个框架
val product = new Product(myCat) with Listening[Category] {
def event(cat: Category) = ??? //strut your stuff here
}
另一种解决方案是避免所有的连接,只需在RepositoryComponent中注册更新闭包列表
}
而产品只需添加自己的更新功能
catRep.categoryUpdates +:= (cat) => p.event(cat)
在您的示例中,您使用Main实例化CategoryRepository,但在我的示例中,它发生在一个trait中,这意味着trait将通过产品的更新方法,这意味着CategoryRepository的trait知道产品。这也是我不想要的。你能用事件来代替吗?也许你应该展示你的类是如何构造的,以及你想在哪里添加事件监听器。或者你将如何处理代表。嗨,你能分享一个用C语言处理的例子吗?或者使用伪代码。为了弄清楚你在问什么,我不知道C语言的确切语法,但我知道你可以使用delegate并使用+=操作符添加一个事件监听器。我只是不知道Scala是否有类似的东西……不要重新定义Product,它是Scala类型系统中的一个关键内置特性—所有元组和所有case类都派生自Product。我并不真正称之为Product。这只是为了解释我的问题。
trait CategoryRepositoryComponentImpl extends CategoryRepositoryComponent {
val categoryRepository = new categoryRepositoryImpl
//public listeners, they should be encapsulated
var categoryUpdates: Seq[Category => Unit]
[...]
def updateAttribute(id:String, request:UpdateCategoryItem): String = {
val cat = dbRepository.get(id)
cat.update(request)
dbRepository.save(cat)
//send the update to the channel
categoryUpdates.foreach(_.apply(cat))
}
}
catRep.categoryUpdates +:= (cat) => p.event(cat)