在scala的函数式编程中选择副作用和良好的API设计

时间:2013-04-19 18:01:00

标签: oop scala functional-programming

我正在移植到scala我编写的java应用程序作为学习练习。部分原因是使用直接通过TCP协议与另一台机器进行通信。该协议有2层(应用程序和传输)以及相应的标题和预告片。所以给定的消息看起来像

  

tHeader | aHeader |消息| aTrailer | tTrailer

我想过使用

trait Layer{
   def write(s:String) : Unit
   def read :String
}

每个图层都会使用其标题|预告片完成消息并将其传递给下一个图层。然后,我会有一个TransportLayer和一个ApplicationLayer,我可以将其组合在像

这样的实现中
 val layer = new TcpLayer with ApplicationLayer with TransportLayer

我很高兴这个设计,它允许我随意重用组件。然后我的困境出现了:

  • 为避免副作用,write方法不应返回Unit,而应返回已修改的String,然后应将其发送。这样可以最大限度地减少副作用,简化测试,但是客户端代码需要通过套接字本身发送已完成的String(已经有副作用,但不能绕过那个,或者?)。
  • 由于客户端代码应该“触发并忘记”,因此它应该能够在给定write上调用Layer并且不关心修改后的String(可能是无论如何他都是胡言乱语。因此我认为返回Unit是返回值的正确选择。

关于哪个版本更具功能性编程的任何深思熟虑的见解 - 友好?

1 个答案:

答案 0 :(得分:1)

如果唯一的副作用是在套接字中,那么这个怎么样:

val layers = new TcpLayer with ApplicationLayer with TransportLayer
socket.write (layers.write (message))
unitTestEngine.check (layers.write (message))

或者如果客户只有layer可以使用,那么:

val layers = new TcpLayer (socket) with ApplicationLayer with TransportLayer
layers.sink (layers.write (message))
unitTestEngine.check (layers.write (message))

其中sink是返回Socket实例的方法。