0

我有一个 Scala 程序,它有几个类和很多通用代码。很多代码都是通用的,所以你有这样的东西(使用 TypeTags 来保存类型信息):

object ModelA {

    def update(id: UUID, changes: Map[String, Any]) = {
        Validate.partialInstanceOf[ModelA](changes) match {
            ...
        }
    }

}

和 ...

object ModelB {

    def update(id: UUID, changes: Map[String, Any]) = {
        Validate.partialInstanceOf[ModelB](changes) match {
            ...
        }
    }

}

我对 Scala 还很陌生,所以我想知道 DRYify 这段代码的最佳方法是什么。我看到了两种可能性:特征或助手类。这就是我对这个特征的想法:

trait Model[M <: Model] {
    def update(id: UUID, changes: Map[String, Any]) = {
        Validate.partialInstanceOf[M](changes) match {
            ...
        }
    }
}

object ModelA extends Model[ModelA]
object ModelB extends Model[ModelB]

...这就是我对助手类的想法:

object ModelHelper {
    def update[M](id: UUID, changes: Map[String, Any]) = {
        Validate.partialInstanceOf[M](changes) match {
            ...
        }
    }
}

object ModelA {

    def update(id: UUID, changes: Map[String, Any]) = {
        ModelHelper.update[ModelA](id, changes);
    }

}
...

我的问题是:什么是更惯用的 Scala 方法?将子类型传递给父特征对我来说似乎有点恶心。这样做可以吗?

4

2 回答 2

3

使用 trait 更为惯用,因为它是 DRYer。Scala 库无处不在,例如:

object ArrayBuffer extends SeqFactory[ArrayBuffer] ...
于 2013-07-24T20:53:37.800 回答
2

如果您可能想要混合提供不同方面功能的多个特征,所有这些都需要知道它们正在使用的特定类型,您可能需要考虑如下模式:

trait Updatable {
    type M
    def update(id: UUID, changes: Map[String, Any]) = {
        Validate.partialInstanceOf[M](changes) match {
            ...
        }
    }
}

trait Jsonable {
    type M
    def toJson(model: M) = {
        ...
    }
}

... other functionality traits ...

object ModelA extends Updatable with Jsonable with ... { type M = ModelA.type }
object ModelB extends Updatable with Jsonable with ... { type M = ModelB.type }
class ModelC extends Updatable with Jsonable with ... { type M = ModelC } // Example for class types rather than objects, if that is relevant.

然后,您可以独立测试每个特征的功能,而不必开始编写类似的东西object ModelD extends Updatable[ModelD] with Jsonable[ModelD] with ...

于 2013-07-24T21:11:18.063 回答