self 类型在这里并不重要。从另一个类继承公开该类的公共方法,而不管任何自身类型。因此,任何从具有公共方法的类的继承都可以说是打破了单一职责原则。
如果trait
它打算用于依赖注入,那么它应该使其方法protected
不被暴露。
trait Output {
protected def output(str: String): Unit
}
trait ConsoleOutput extends Output {
protected override def output(str: String): Unit = println(str)
}
评论接受的答案
接受的答案声称“提供输出的责任仍然在于实现的组件Output
”。这是不正确的,并且显示了类型和实现之间的混淆。
对象的行为是由它的类型指定的,而不是它的实现(里氏替换原则)。类型是告诉用户对象可以做什么的合同。因此,指定职责的是类型,而不是实现。
类型Sample with ConsoleOutput
有output
来自Object
类型的方法和来自类型的doSomething
方法Sample
。因此,它有责任提供这两种方法的实现。output
in的实现ConsoleOuput
与类型无关,因此与谁负责它无关。
该Sample with ConsoleOutput
对象可以轻松地覆盖 的实现,output
在这种情况下,它显然会负责该方法,而不是ConsoleOutput
. Sample with ConsoleOutput
选择不改变实现的事实output
并不意味着它不对它负责。当实现改变时,对象的职责不会改变。
该原则是软件工程的五个SOLID原则中的第一个。正如 Wikipedia 解释的那样,“单一职责原则 [] 指出每个模块或类都应该对软件提供的单个功能部分负责,并且该职责应该完全由类封装。”
换句话说,不要这样做:
class MultipleResponsibilities {
def computePi(places: Int): List[Int]
def countVowels(text: String): Int
}
但改为这样做:
class PiComputer {
def computePi(places: Int): List[Int]
}
class VowelCounter {
def countVowels(text: String): Int
}
computePi
并且countVowels
是程序功能的不同部分,因此它们应该封装在不同的类中。
第三个 SOLID 原则是Liskov 替换原则,它说对象的功能应该完全取决于类型,并且不应该受到实现的影响。您应该能够更改实现并仍然以相同的方式使用对象并获得相同的结果。
由于对象的功能完全由对象的类型定义,因此对象的职责也完全由类型定义。改变实施并不会改变责任。