如何混合明显不兼容的范例:OOP和FP?

时间:2011-10-27 15:32:20

标签: oop scala coding-style functional-programming paradigms

回读一些我的Scala代码,我注意到它是功能性的或面向对象的。

实际上,我不知道如何调解不可变类型和纯函数所隐含的无副作用规则以及OO的前提,其中方法就地修改实例状态,这显然是副作用。

我正在研究的一个解决方案是使所有方法返回具有适当状态修改的当前实例的克隆。看起来很渴望,但在我决定对代码进行并列化时可能有所帮助,对吗?

混合这两种范式的最佳做法是什么?什么是平衡?

感谢。

4 个答案:

答案 0 :(得分:9)

不可变类是桥接OO和FP的一种非常好的方法。 Scala的Collection Library是混合OO,不可变对象和函数式编程的一个很好的例子。

在您自己的代码中,Scala的case classes确实有助于实现不可变对象,因为它们有一个copy方法,可以用来替代构建器模式。

// begin cheesy example
case class Circle(center: (Double, Double), radius: Double) {
  def move(c: (Double, Double)) = copy(center = c)
  def resize(r: Double) = copy(radius = r)
  def area = math.Pi * radius * radius
}

您还可以观看Rich Hickey的演讲Persistent Data Structures and Managed ReferencesAre We There Yet吗?两者都做得很好,解释了对不变性的需求,以及它如何帮助我们推理国家。他谈到了关于Clojure的一切,但他的观点同样适用于Scala。

答案 1 :(得分:3)

我认为我实际上对你构建这个问题的方式有疑问:

  

实际上,我不知道如何调解不可变类型和纯函数所隐含的无副作用规则以及OO的前提,其中方法就地修改实例状态,这显然是副作用。

我不会说对象字段的变异操作是OO的核心“前提”。完全没有(尽管相反,我认为不变性是FP的核心前提)。对我而言,OO是一种思考程序模块化的方式。

在我的(也许是扭曲的)思维模式中,即使是Haskell--一种主张常常以OO风格思维畏缩的语言 - 仍然体现了一些OO概念,在某种意义上它具有模块系统,各种方式封装实现细节数据类型等等。另一方面,虽然它非常笨拙和恶化,但我的Java代码倾向于大量使用currying等基本功能概念。

换句话说,我认为这两种方法在某种意义上是互补的。

现在,在一个不太理论化和更具螺栓的水平......让我们说你有类似的东西:

class Foo(val a : A, val b : B, val c : C) {
  def setB(newb : B) : Foo = new Foo(a, newb, c)
}

...所以你可以按照原帖中的建议说newFoo = foo.setB(b)。我会说这是完全很好的风格,而不是引起关注(关于性能或可读性或任何东西)。你会在Scala库中看到大量的不可变集合类。

答案 2 :(得分:0)

你可能想检查Scala编程的Functional Programming chapter(它是available free online)以获得一些提示。

FP它不仅仅是关于线程。高阶函数可以帮助您清理和干燥代码,使其看起来更优雅。

答案 3 :(得分:0)

  

使所有方法返回当前实例的克隆

如果你检查jQuery是如何做到的,它会使用一种名为Method Chaining的技术 否则返回void的每个方法都会返回$ this,因此您可以继续调用方法。这就是为什么jQuery对象不会破坏javascript中的传统过程用户代码。