在Scala中,将算法写成类或对象的形式有哪些缺点?

4
class A {
  def algorithmImplementation (...) = { ... }
}

object A {
  def algorithmImplementation (...) = { ... }
}

在什么情况下应该使用 class,什么情况下应该使用 object(例如实现一个算法,如上所示的 Dijkstra 算法)?
在做出这样的决定时应考虑哪些标准?
目前,我真的看不出使用 class 的好处。

1
还有一种很有用的模式,就是把所有东西都定义在一个“trait”中,然后让一个“object”继承这个“trait”。这种模式在这个问题中有更详细的解释:https://dev59.com/y1bUa4cB1Zd3GeqPDv2I。 - Jean-Philippe Pellet
2个回答

6
如果你只有一个实现,这很大程度上可以是一个判断调用。你提到了Dijkstra算法,它运行在图上。现在你可以编写该算法以将图对象作为显式参数。在这种情况下,该算法可能会出现在Graph单例对象中。然后它可能会被称为类似于Graph.shortestPath(myGraph,fromNode,toNode)的东西。
或者你可以在Graph类中编写算法,这样它就不再将图作为显式参数。现在它被称为类似于myGraph.shortestPath(fromNode,toNode)的东西。
后一种情况可能更有意义,特别是当有一个主要参数(例如图形),尤其是作为算法的上下文时。但这可能取决于你更喜欢哪种语法。
然而,如果你有多个实现,平衡更倾向于类方法,特别是当选择哪种实现更好取决于表示的选择时。例如,你可能有两个不同的shortestPath实现,一个在邻接矩阵上工作得更好,另一个在邻接表上工作得更好。使用类方法,你可以轻松地为两种不同的表示方式拥有两个不同的图形类,并且每个类都可以有自己的shortestPath实现。然后,当你调用myGraph.shortestPath(fromNode,toNode)时,你自动获得正确的实现,即使你不知道myGraph是使用邻接矩阵还是邻接表。(这就是面向对象的全部意义。)

5

类可以有子类来覆盖实现,对象无法被子类化。类还可以是类型参数化的,而对象不行。

每个容器中只有一个对象实例,或者至少有一个实例。类有多个实例。这意味着类可以使用值进行参数化。

class A(param1 : int, param2 : int) {
    def algorithmImplementation(arg : List[String]) = // use arg and params
}

这可以像复用一样使用

val A42_13 = new A(42, 13)
val result1 = A42_13.algorithmImplementation(List("hello", "world"))
val result2 = A42_13.algorithmImplementation(List("goodbye", "cruel", "world"))

为了让这个例子与Djikstra算法相关,想象一下你想编写一个实现该算法的版本,可以重用于多种节点类型。那么,您可能希望通过节点类型、用于测量距离的度量类型和用于计算距离的函数来参数化。
val Djikstra[Node, Metric <: Comparable[Metric]](distance : (Node, Node) => Metric) {
    def compute(node : Node, nodes : Seq[Node]) : Seq[Metric] = {...}
}

每次计算Djikstra时,您需要为每种不同类型的节点/度量/距离函数创建一个Djikstra实例,并重复使用该实例,而无需每次都传递所有信息。

总之,类更加灵活。在需要灵活性时使用它们。否则,对象就可以了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接