10

在 OOP 中,与接口而不是实现对话是一种很好的做法。所以,例如,你写这样的东西(Seq我的意思是scala.collection.immutable.Seq:)):

// talk to the interface - good OOP practice
doSomething[A](xs: Seq[A]) = ???

不是以下内容:

// talk to the implementation - bad OOP practice
doSomething[A](xs: List[A]) = ???

但是,在纯函数式编程语言(例如 Haskell)中,您没有子类型多态性,而是通过类型类使用临时多态性。因此,例如,您有列表数据类型和列表的一元实例。您无需担心使用接口/抽象类,因为您没有这样的概念。

在 Scala 等混合语言中,您同时拥有类型类(实际上是通过模式,而不是像 Haskell 中的一等公民,但我离题了)和子类型多态性。在scalaz,cats等等中,你有具体类型的单子实例,当然不是抽象的。

最后的问题是:鉴于 Scala 的这种混合性,您是否仍然尊重 OOP 规则来与接口对话,或者只是与具体类型对话以直接利用函子、单子等,而无需在需要时转换为具体类型。他们?换句话说,即使您想采用 FP 而不是 OOP,在 Scala 中与接口对话是否仍然是一种好习惯?如果不是,如果您选择使用List,并且后来您意识到 aVector会是更好的选择,该怎么办?

PS:在我的示例中,我使用了一种简单的方法,但同样的推理也适用于用户定义的类型。例如:

case class Foo(bars: Seq[Bar], ...)
4

2 回答 2

1

我要在这里攻击的是您的“具体与界面”概念。这样看:每种类型都有一个接口,一般意义上的“接口”。“具体”类型只是一种限制情况。

所以让我们从这个角度看一下 Haskell 列表。列表的界面是什么?好吧,列表是一种代数数据类型,所有这些数据类型都具有相同的接口和契约的一般形式:

  1. 您可以根据其arities 和参数类型使用其构造函数构造该类型的实例
  2. 您可以通过根据参数类型和参数类型匹配它们的构造函数来观察类型的实例;
  3. 构造和观察是相反的——当你对一个值进行模式匹配时,你得到的正是放入其中的内容。

如果您从这些术语来看,我认为以下规则在任一范例中都非常有效:

  • 选择接口和契约与您的要求 完全匹配的类型。
    • 如果他们的合约弱于您的要求,那么他们将不会维护您需要的不变量;
    • 如果他们的合同比您的要求强,您可能会无意中将自己与“额外”细节联系起来,并限制您以后更改程序的能力。

所以你不再问一个类型是“具体的”还是“抽象的”——只是它是否符合你的要求。

于 2016-05-10T18:54:48.143 回答
0

这是我在这个主题上的两分钱。在 Haskell 中,您有数据类型 (ADT)。您同时拥有列表(链表)和向量(int 索引数组),但它们不共享一个共同的超类型。如果您的函数需要一个列表,则不能将其传递给向量。

在 Scala 中,作为一种混合 OOP-FP 语言,您也具有子类型多态性,因此您可能不在乎客户端代码是否通过 aList或 a Vector,只需要 a Seq(可能是不可变的)就可以了。

我想要回答这个问题,你必须问自己另一个问题:“我想完全接受 FP?”。如果答案是肯定的,那么您不应该使用SeqOOP 意义上的任何其他抽象超类。当然,这个规则的例外是在 Scala 中定义 ADT 时使用 trait/abstract 类。例如:

sealed trait Tree[+A]
case object Empty extends Tree[Nothing]
case class Node[A](value: A, left: Tree[A], right: Tree[A]) extends Tree[A]

在这种情况下,当然需要Tree[A]作为一种类型,然后使用例如模式匹配来确定它是否是EmptyNode[A]

我想我对这个主题的感觉得到了红皮书Scala 中的函数式编程)的证实。他们从不使用Seq, butListVector。此外,haskellers 不关心这些问题,只要他们需要链表语义就使用列表,而只要他们需要 int-indexed-array 语义就使用向量。

另一方面,如果您想拥抱 OOP 并将 Scala 用作更好的 Java,那么可以,您应该遵循 OOP 最佳实践来接口而不是实现进行对话。

如果您在想:“我宁愿选择主要功能”,那么您应该阅读 Erik Meijer 的The Curse of the Excluded Middle

于 2016-05-12T12:31:36.060 回答