混合OO和Functional设计

摘自 http://www.jdon.com/43907

面向对象定位于系统高层次,面向函数编程是定位于低层次. 来自
Tell Above, and Ask Below - Hybridizing OO and Functional Design重新定义了面向对象,纠正了以往对OO 的错误观点:

Object-orientation is better for the higher levels of a system, and functional programming is better for the lower levels. 面向对象定位于系统高层次(更靠近人),面向函数编程是定位于低层次(更靠近机器).

文章首先各自重申定义了面向函数FP和面向对象OO 的定义:

(1)函数式编程是为了减少副作用,当没有副作用时,你就能透明引用,可以将表达式从一个地方拷贝到另外一个地方,只要给予同样输入,无论如何调用,总是给出同样的输出。这称为purity纯度。

纯度能够激活懒加载,在面向函数语言中,calling a function调用一个函数和apply a function应用一个函数意义是完全不一样的。

(2) 关于面向对象,作者引用了最初原始的对象定义:Alan Kay认为对象是道法自然处理复杂系统的方式,使用对象方式来处理复杂软件系统,在生物学中,一个有机体中有很多神经元Cell,这些神经元之间通过化学 消息进行彼此联系,这点非常类似Smalltalk 使用消息发送message send而不是功能调用functional call,两者不只是巧合。

对象结构的好处是它更显式强调Play,而不是Player,正如Alan Kay认为:消息比对象本身更加重要(banq注:JdonFramework基于事件 消息的特性反映了OO 本质),这在生物学也同理,你不可能通过杀死一个Cell来搞垮整个有机体,这就证明了越接近Erlang的处理模型就越是典型的面向对象系统。

早在2000年, Dave Thomas 和 Andy Hunt写了一段设计指导,称为‘Tell, Don’t Ask.’(只是告诉交代,别索要),当你吩咐对象应该为你做什么即可,而不是让他们带着他们数据,由你来处理这些数据,这样才会带来完美的封装。 (banq注:因为对象只要您吩咐一身,就自己内部搞定了。)

在生物学中,神经元之间化学消息是异步的,一个神经元发送消息并不会堵塞直 至接受到消息,但是,目前很多典型的面向对象系统是这样的(通常的方法调用就是这样,调用者堵塞直至被调用者的方法处理完毕),当我们调用另外一个对象的 方法,必须在那里等待直至那个对象的方法返回一个结果给我们,其实我们还有其他事情要做,对象很忙,这种同步方式调用实际侵犯了 'Tell, Don't Ask'原则, 因为,等待返回结果是典型的‘ask’(索要结果)。

如果我们认为面向对象OO 类似生物神经元,那么目前我们大多数所谓OO 技术是错误的. 在这些编程语言如Java .NET中有类和对象,但是一旦我们实现同步方法调用,这些概念就不再是他们名字那样了,名非名了。

那么有比这些所谓OO 更加真正OO 吗?是的,IT架构中的消息系统。

前面文章提到:消息系统才是真正的OO 。下面以代码说明:


Class A{
  void
 m(){
  }
}
Class B{
   void
 m1(){
      ...
      a.m(); //同步堵塞方法 
 ... } } 


代码中,B对象中a.m()就是上文提到的同步堵塞方法,B在这里Ask索要A的m方法结果,自己的事情干不了,这是不符合类似神经元的工作原理,如果真是这样,可能是神经病的表现了。

那么,异步方法如何实现呢?Erlang或Scala的trait都能够优雅实现,而在Java中,可以使用基于Disruptor的Jdonframework 实现,具体可见:
非堵塞并发编程

以上B代码使用Jdon框架改写大概如下:

@Send ("事件名称")
a.m();

通过元注解即可完成异步方法调用。

真正OO 应该是异步消息交互的,这点在UML的顺序图中也是如此,如下图:





[该贴被banq于2012-04-23 13:16修改过]


混合OO和Functional设计_第1张图片

综上所述,我们在看面向对象设计和函数编程时,他们其实是不矛盾,有并行存在的部分。

OO最适合Tell吩咐,当你吩咐时,对象封装切分其实最大化解耦实体之间的耦合,为了进一步防止耦合,你必须让你的消息异步发送。这些都是通过 tell 模型做到的.

函数编程FP最适合ask索取. 其实在纯函数编程中,如果一个函数方法不返回任何结果几乎是毫无意义的,除非是为了考虑副作用(边际影响),函数化Functional纯洁性purity将会激活懒加载,这非常类似OO 中激活异步一样。(banq注:在JdonFramnework中,可以用事件 实现消息发送,也可以实现懒加载,特别是数据库数据懒加载。)

好了,如果我们接受这些预设,那么我们如何组织我们的系统呢?

假设顶层有一个函数式层,当里面的表达式被演算后,执行消息的发送,但是这会造成系统理解上的问题,也会产生副作用,破坏函数的纯洁性。

那么有没有其他方向呢? 如果我们将对象层放在顶部,允许对象使用底部的函数片段?这好像真的没有什么问题。无副作用的函数适合内部机制,面向对象非常适合高层,能够解耦信息系统是最重要的。

现在有一个疑问,象Scala这样允许程序在任何抽象层次混合对象和函数,甚至你能够使用函数进行查询过滤对象,微软的LINQ技术也是在对象层面上建立函数层面,这些好像违背上面的预设。

无论如何,我们已经知道,真正的面向对象在现代软件架构中是存在服务或消息层面,那么在这样架构下,非常适合“tell above , ask below.”在上面吩咐,在下面索要。


你可能感兴趣的:(function)