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

Ale*_*ari 8 oop paradigms functional-programming coding-style scala

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

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

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

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

谢谢.

lee*_*777 9

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

在您自己的代码中,Scala的case类实际上有助于实现不可变对象,因为它们有一个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
}
Run Code Online (Sandbox Code Playgroud)

你也可以看看Rich Hickey的持久性数据结构和管理参考资料,我们还有吗?两者都做得很好,解释了对不变性的需求,以及它如何帮助我们推理国家.他谈到了关于Clojure的一切,但他的观点同样适用于Scala.


mer*_*ict 3

我想我实际上对你的框架方式有异议:

事实上,我不知道如何协调不可变类型和纯函数隐含的无副作用规则与面向对象的前提,其中方法就地修改实例状态,这显然是副作用。

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

在我(也许是扭曲的)心态中,即使是 Haskell——一种其拥护者常常对 OO 风格思维感到畏缩的语言——仍然体现了一些 OO 概念,因为它有一个模块系统,封装数据类型实现细节的各种方式,另一方面,虽然我的 Java 代码非常笨拙且令人恼火,但它倾向于大量使用基本的函数概念,例如柯里化。

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

现在,在更少的理论和更具体的层面上......假设你有这样的东西:

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

...所以你可以newFoo = foo.setB(b)按照你在原帖中的建议说。我想说这是完全好的风格,不需要担心(关于性能或可读性或其他任何事情)。您将在 Scala 库中的不可变集合类中看到很多这样的情况。