Mik*_*yer 15 scala object-oriented-analysis
有两种方法可以为scala中继承相同特征的两个不同类定义方法.
sealed trait Z { def minus: String }
case class A() extends Z { def minus = "a" }
case class B() extends Z { def minus = "b" }
Run Code Online (Sandbox Code Playgroud)
替代方案如下:
sealed trait Z { def minus: String = this match {
case A() => "a"
case B() => "b"
}
case class A() extends Z
case class B() extends Z
Run Code Online (Sandbox Code Playgroud)
第一种方法重复方法名称,而第二种方法重复类名称.我认为第一种方法最好使用,因为代码是分开的.但是,我发现自己经常使用第二个方法来处理复杂的方法,因此可以非常容易地添加其他参数,例如:
sealed trait Z {
def minus(word: Boolean = false): String = this match {
case A() => if(word) "ant" else "a"
case B() => if(word) "boat" else "b"
}
case class A() extends Z
case class B() extends Z
Run Code Online (Sandbox Code Playgroud)
这些做法之间有什么其他差异?如果我选择第二种方法,是否还有等待我的错误?
编辑: 我引用了开放/封闭原则,但有时,我不仅要修改函数的输出,这取决于新的案例类,还要修改输入,因为代码折射.有没有比第一个更好的模式?如果我想在第一个示例中添加先前提到的功能,这将产生重复输入的丑陋代码:
sealed trait Z { def minus(word: Boolean): String ; def minus = minus(false) }
case class A() extends Z { def minus(word: Boolean) = if(word) "ant" else "a" }
case class B() extends Z { def minus(word: Boolean) = if(word) "boat" else "b" }
Run Code Online (Sandbox Code Playgroud)
我会选择第一个.
为什么?仅保持开放/封闭原则.
实际上,如果你想添加另一个子类,让我们说case class C
,你必须修改supertrait/superclass来插入新的条件...丑陋
您的场景在Java中具有类似于模板/策略模式的条件.
更新:
在您的上一个场景中,您无法避免输入的"重复".实际上,Scala中的参数类型是不可推断的.
最好是使用内聚方法而不是将整个内部混合在一个方法中,该方法提供与union期望的方法一样多的参数.
想象一下你的supertrait方法中的十个条件.如果你无意中改变了每个人的行为怎么办?每次更改都会有风险,每次修改时都应该运行supertrait单元测试...
此外,无意中改变输入参数(不是行为)根本不是"危险的".为什么?因为编译器会告诉你参数/参数类型不再相关.如果你想改变它并为每个子类做同样的事情...问你的IDE,它喜欢一键重构这样的事情.
正如此链接所解释的:
为什么开放式原则很重要:
无需单元测试.
无需了解重要且庞大的类的源代码.
由于绘图代码被移动到具体的子类,因此在添加新功能时会降低影响旧功能的风险.
更新2:
这里有一个避免输入重复的样本符合您的期望:
sealed trait Z {
def minus(word: Boolean): String = if(word) whenWord else whenNotWord
def whenWord: String
def whenNotWord: String
}
case class A() extends Z { def whenWord = "ant"; def whenNotWord = "a"}
Run Code Online (Sandbox Code Playgroud)
谢谢类型推断:)
从 开始Scala 3
,您可以使用特征参数(就像类有参数一样),这在这种情况下简化了很多事情:
trait Z(x: String) { def minus: String = x }
case class A() extends Z("a")
case class B() extends Z("b")
A().minus // "a"
B().minus // "b"
Run Code Online (Sandbox Code Playgroud)