经过一些讨论后,我想强调,这个问题与在产品/总和类型的OOP中使用继承有关,如在FP中,反之亦然。你喜欢什么,你的建议是什么!所以......
我有些怀疑 - 定义以下内容的更清晰(更清晰)的方法是什么:
例如我更喜欢
sealed trait Shape
case class Square(length: Int) extends Shape
case class Rhombus(length: Int) extends Shape
而不是
sealed abstract class Shape(val length: Int)
case class Square(override val length: Int) extends Shape(length)
case class Rhombus(override val length: Int) extends Shape(length)
但是
def draw(shape: Shape): String = shape match {
case Square(length) => length.toString
case Rhombus(length) => length.toString
}
而不是
def draw(shape: Shape): String = shape.length.toString
类型的定义在第一种方法中看起来更简洁,更一致,但如果我需要为所有形状设置通用逻辑,如draw
方法,则第二种方法看起来更清晰。
答案 0 :(得分:6)
这将是首选方式:
sealed trait Shape {
def length: Int
}
case class Square(length: Int) extends Shape
case class Rhombus(length: Int) extends Shape
以下是您的代码中的一些非惯用内容:
abstract class
主要是java兼容性的东西,尽可能使用特征override
未实现的字段感觉不对val
,总是使用defs
作为摘要,这些可以用其他东西进行改进答案 1 :(得分:0)
摘自本书https://leanpub.com/fpmortals/
我们也可以使用
sealed trait
代替sealed abstract class
,但是使用abstract class
具有二进制兼容性优势。仅当您需要创建具有多重继承的复杂ADT时,才需要sealed trait
。
答案 2 :(得分:0)
这不是一个坏建议,但对我来说,它是对Product类型的更多继承。有了特质,它可能更多是mixin,但是仍然!长度就是所有形状的一部分,即使您不需要它。
如果不是所有形状都需要它,那么就不用
def draw(shape: Shape): String = shape.length.toString
首先,没有得到它不是一个缺点。但是你也可以拥有
sealed trait Shape
sealed trait HasLength extends Shape {
def length: Int
}
// Shape optional, but may be clearer for this case
case class Square(length: Int) extends Shape with HasLength
case class Rhombus(length: Int) extends Shape with HasLength
def draw(shape: Shape): String = shape match {
case shape: HasLength => shape.length.toString
case ... => ... // handle those shapes which don't have length
}