在Scala 3中动态检查子类关系
我正在尝试向从PHP8到Scala 3的DomainEventHandlers和-Dispatcher提供解决方案。处理程序应指定他们可以处理的事件列表(最好以类型的方式,最好是通过其类)。处理程序已在调度程序中动态注册,该调度员应从每个处理程序的列表元素到这些事件的处理程序列表汇总地图。
当与调度员提出事件时,它应检查当前事件的类,按照地图的键检查当前事件的键,并在每个处理程序列表中将事件传递给每个处理程序的键,仅当事件类别与事件类别相同时或由密钥指定的类的子类。
在诸如PHP8之类的动态键入的OOP语言中,这很容易 - 一个处理程序存储一个类名称的列表,可以简单地通过[className] :: class
来对其进行重新验证,然后调度程序通过$ event :: class
并执行is_a
- 检查每个hashmap-key的 - 检查精确匹配和子类关系。
在Scala 3中,我似乎找不到一种很好的方法来做到这一点。通过getClass
或class [?]
与基础Java反射一起使用,由于Scala和Java类型 - 系统之间的不匹配而产生问题(特别是,拖延$ <
$ < /代码>是否存在)。在Scala 2中,标签可能是要走的路 - 但是Scala 3反射是另一种野兽,我还没有找到一种利用它来实现上述方法的方法,并感谢建议。
具体而言,假设我们
trait DomainEvent[D1 <: Serializable, D2 <: Serializable, A <: Aggregate]
extends Event[D1, D2]:
type AggregateType = A
val aggregateIdentifier: (String, UUID)
def applyAsPatch(aggregate: AggregateType): AggregateType
trait DomainEventHandler:
val handles: List[???]
def handle(event: DomainEvent[?, ?, ?]): ZIO[Any, Throwable, Unit]
object DomainEventDispatcher:
val registeredHandlers: scala.collection.mutable.Map[???, List[DomainEventHandler]] =
scala.collection.mutable.Map()
def registerHandler(handler: DomainEventHandler): Unit = ???
def raiseEvent(event: DomainEvent[?, ?, ?]): ZIO[Any, Throwable, Unit] = ???
不确定在domaineventhandler列表中和调度程序的映射中使用的使用方法 -
register> register Handler
和raiseevent
代码> - 实施将随之而来。
I am trying to port a solution for DomainEventHandlers and -Dispatcher from PHP8 to Scala 3. Handlers should specify a list of events they can handle (in a type-safe way, preferably, by their classes). Handlers are dynamically registered with the Dispatcher, which should aggregate a map from the elements of the lists from each Handler to a List of Handlers for those events.
When an event is raised with the Dispatcher, it should check the class of the current event against the keys from the map, and pass the event to each Handler in each list of Handlers for a key if and only if the event's class is identical to or a subclass of the class specified by the key.
In dynamically typed OOP languages like PHP8, this is easy - a Handler stores a list of class-names, which can be reified simply by [ClassName]::class
, then the Dispatcher gets the event's class via $event::class
and performs an is_a
-check for each HashMap-key, which checks both exact match and subclass-relationship.
In Scala 3, I can't seem to find a good way to do this. Working with underlying Java-reflections via getClass
or Class[?]
produces problems due to the mismatch between the Scala and Java type-systems (specifically, trailing $
being either present or not). In Scala 2, Tags would probably have been the way to go - but Scala 3 reflection is a different beast, and I have not found a way to utilize it to implement the above, and would appreciate advice.
Concretely, let's say we have
trait DomainEvent[D1 <: Serializable, D2 <: Serializable, A <: Aggregate]
extends Event[D1, D2]:
type AggregateType = A
val aggregateIdentifier: (String, UUID)
def applyAsPatch(aggregate: AggregateType): AggregateType
trait DomainEventHandler:
val handles: List[???]
def handle(event: DomainEvent[?, ?, ?]): ZIO[Any, Throwable, Unit]
object DomainEventDispatcher:
val registeredHandlers: scala.collection.mutable.Map[???, List[DomainEventHandler]] =
scala.collection.mutable.Map()
def registerHandler(handler: DomainEventHandler): Unit = ???
def raiseEvent(event: DomainEvent[?, ?, ?]): ZIO[Any, Throwable, Unit] = ???
I am unsure what to use in place of ???
in the DomainEventHandler's List and the Dispatcher's Map - the registerHandler
and raiseEvent
-implementations will follow from that.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好吧,如果您匹配的具体事件类未参数化,这很简单:
但是,如果您想在
event [int]
之类的内容上匹配,这会使事情变得更加困难。我找不到一种很好的方法(尽管我绝不是Scala 3功能的专家)。不确定他们为什么放弃classtag支持...我将其视为与此类类型参数匹配的标志,不再被认为是一个好练习,而解决问题的“正确”解决方案现在正在命名您想要匹配的所有类没有类型参数。
Well, if your concrete event classes that you match aren't parametrized, it's pretty simple:
But if you want to match on things like
Event[Int]
, that makes things significantly more difficult. I wasn't able to find a good way to do it (though, I am by no means an expert in scala 3 features).Not sure why they dropped ClassTag support ... I am taking it as a sign that matching on type parameters like this is no longer considered a good practice, and the "proper" solution to your problem is now naming all classes you want to match without type parameters.