此问题与this one有关。 我有一整套的Config类型的类,所有这些类都是使用构建器模式构建的。因此,我也有ConfigBuilder类,它们也形成一个层次结构,因为许多实现共享相同的行为。
我想要实现的是ConfigBuilder公开了一种方法build
,该方法始终执行以下步骤:验证参数(如果无效,则抛出异常)并构建Config。当然,我想用最少的代码重复做到这一点。实际上,构建方法可以理想地分为两部分:Config的所有实现共享的参数的通用构建,以及每个Config的特定于实现的构建。
这是超类的一个例子
abstract class Config {
def name: String
def query: String
def sourceTable: String
}
abstract class ConfigBuilder {
// common variables are set through setters by the user, which finally calls build
def build = {
validate
val sourceTable = extractFrom(query) // private local method
// it will contain more fields, extracted from the ones set by the user
buildInternal(sourceTable)
}
def validate = {
if(name == null) throw new Exception() // and all common checks
}
abstract def buildInternal(s:String): Config
}
这是一个实现
case class Factlog private (
name:String, query:String, sourceTable:String, description: String)
class FactlogBuilder extends ConfigBuilder {
// description is set through setters by the user
def validate = {
super.validate()
if(description == null) throw new Exception()
}
def buildInternal(s:String) =
Factlog(name,query,s,description)
}
此代码段有效,但我想了解这是否是实现build
和buildInternal
方法的最佳方法。
buildInternal
签名将随任何新的Factlog特定参数而变化,因此解决方案是将sourceTable
的计算结果放到ConfigBuilder中,方法构建之外sourceTable
var sourceTable = _
,然后在验证方法调用之后,为其提供方法extractQuery
返回的值我很想使用方法3,但是我认为这并不是应该如何使用Scala。我相信,有更好的方法来构成这些层次结构。
P.S。参数列表肯定会随着时间增长,所以这是我必须考虑的问题。而且,Spark功能促进了构建器模式的使用,目前我无法避免使用它。