scala api design:我可以避免不安全的演员表或泛型
我正在编写一个提供分布式算法的库.想法是现有的应用程序可以添加库以使用该算法.该算法位于库模块中,它通过网络后面的网络抽象实际数据传输.使用该算法的应用程序必须提供实际的网络传输代码.在代码中,它看起来如下所示:
// library is really a separate project not a single object object Library { // handle to a remote server trait RemoteProcess // concrete server need to know how to actually send to a real remote process trait Server { def send(client: RemoteProcess,msg: String) } } // the application uses the library and provides the concrete transport object AkkaDemoApplication { // concreate ref is a m wrapper to an actor ref in demo app case class ConcreteRemoteProcess(ref: akka.actor.ActorRef) extends Library.RemoteProcess class AkkaServer extends Library.Server { // **WARNING** this wont compile its here to make my question override def send(client: ConcreteRemoteProcess,msg: String): Unit = client.ref ! msg } } 我考虑过几个选项: >让AkkaServer方法的签名重载库特征方法,然后对ConcreteRemoteProcess执行不安全的转换.育! 选项3的示例如下所示: object Library { trait Server[RemoteProcess] { def send(client: RemoteProcess,msg: String) } } object Application { class AkkaServer extends Library.Server[ActorRef] { override def send(client: ActorRef,msg: String): Unit = client ! msg } } 我尝试了选项3并且它工作但是泛型类型最终被标记在整个库模块的几乎每种类型上.然后有很多协变和逆变的麻烦来编译算法代码.只是为了在一个集成点获得编译时确定性,认知开销非常大.在视觉上,库代码由通用签名控制,就好像理解对于理解库是至关重要的,实际上它完全分散了解库逻辑. 因此,使用遗传工作并给我编译时间肯定,但现在我希望我选择2(模式匹配)的借口“它会在启动时快速失败,如果有人弄错了让我们保持简单”. 我是否缺少一些Scala功能或成语,以获得编译时确定性而没有所有库代码触及但忽略的“高触摸”泛型的认知开销? 编辑我已经考虑过,或许我的代码库被严重考虑因为重构可以将泛型移动到边界.然而,该库已经被重构为可测试性,并且分解为可测试的职责是泛型问题的一部分,这些问题在代码库中被涂抹了.因此我的问题是:一般来说还有另一种技术我不知道要避免泛型为抽象API提供具体的实现吗? 解决方法
我认为你的算法与Akka的结合太紧密了.此外,我假设服务器将数据发送到执行某些操作的远程客户端并发回结果
回答 为什么不 object Library { // handle to a remote server trait RemoteProcessInput trait RemoteProcessResult // concrete server need to know how to actually send to a real remote process and how to deal with the result trait Server { def handle(clientData: RemoteProcessInput) : Future[RemoteProcessResult] } } 具体实现提供了Akka的实现 object Application { class AkkaServerImpl(system: ActorSystem) extends Library.Server { override def handle(clientData: RemoteProcessInput) : ActorRef,msg: String): Future[RemoteProcessResult] = { // send data to client and expect result // you can distinguish target and msg from the concrete input val ref : ActorRef = ??? // (resolve client actor) val msg = ??? // (create your message based on concrete impl) val result = ref ? msg // using ask pattern here // alternatively have an actor living on server side that sends msgs and receives the clients results,triggered by handle method result } } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |