如何避免将实现与蛋糕模式混合的重复
How to avoid duplications of mixing of an implementation with the cake pattern
在我在互联网上找到的所有与 Cake patter 相关的文章中,我都看到了单级依赖关系,这对我来说很清楚。
但是当我开始使用它时,我遇到了一个问题,我不能只在高级 class 中使用服务,我需要在多个地方混合使用它。
例如,如果我有一个服务,并且该服务与一组其他服务一起工作,并且该组中的每个服务都使用一个数据库,我尝试不从这组低级别直接访问数据库服务。我只在高级服务中进行了所有数据库查询。
但在某些情况下很难。
也许这个问题用例子会更清楚:
trait DatabaseServiceComponent{
val databaseService: DatabaseService
trait DatabaseService{
def getSomeData(id: Int, tableName: String): List[String]
def getFriends(id: Int): List[Int]
}
}
trait DatabaseServiceComponentImpl extends DatabaseServiceComponent{
val databaseService: DatabaseService = new DatabaseServiceImpl
class DatabaseServiceImpl extends DatabaseService{
def getSomeData(id: Int, tableName: String): List[String] = ???
def getFriends(id: Int): List[Int] = ???
}
}
trait Scoring { this: DatabaseServiceComponent =>
def importantValues: Set[String]
val tableName: String
def getScore(id: Int): Double = databaseService.getSomeData(id, tableName).count(importantValues)
}
class Scoring1 extends Scoring{this: DatabaseServiceComponent =>
val tableName: String = "s1"
override def importantValues: Set[String] = Set("a", "b")
}
class Scoring2 extends Scoring{this: DatabaseServiceComponent =>
val tableName: String = "s2"
override def importantValues: Set[String] = Set("foo", "bar")
}
class Scoring3 extends Scoring{this: DatabaseServiceComponent =>
val tableName: String = "s3"
override def importantValues: Set[String] = Set("1", "2")
}
// How to implement this correctly?
trait Scoring2FriendsAverage {this: DatabaseServiceComponent =>
val scoring2: Scoring2
def getScore(id: Int):Double ={
val scores = databaseService.getFriends(id).map(scoring2.getScore)
scores.size / scores.sum
}
}
object FriendsScoringProcessor{
val scoring2Friends = new Scoring2FriendsAverage with DatabaseServiceComponentImpl{
val scoring2 = new Scoring2 with DatabaseServiceComponentImpl // I don't like that I have to mix the implementation of a service again
}
def printScores(id: Int): Unit = {
val score = scoring2Friends.getScore(id)
println(score)
}
}
我有一组评分,每个评分都使用一个数据库。我有一个 FriendsScoring,它使用其中一个使用数据库的评分。我希望能够仅将数据库实现混合到 FriendsScoring,并且不要在较低级别的服务中复制它。
我看到一个(可能)好的解决方案是通过隐式构造函数参数为低级服务提供实现。
看起来像蛋糕模式组件和服务的混合级别。
如果我们在服务层使用 Scoring
,那么它不应该出现在蛋糕模式层。
您可能希望将 Scoring
拆分为每个级别的两个嵌套特征,就像您对数据库所做的那样:
trait ScoringComponent {this: DatabaseServiceComponent =>
trait ScoringService {
def getScore(id: Int): Double =
databaseService.getSomeData(id, tableName).
count(importantValues)
}
}
然后你将能够在混合所需的依赖项后使用ScoringService
。
在我在互联网上找到的所有与 Cake patter 相关的文章中,我都看到了单级依赖关系,这对我来说很清楚。
但是当我开始使用它时,我遇到了一个问题,我不能只在高级 class 中使用服务,我需要在多个地方混合使用它。
例如,如果我有一个服务,并且该服务与一组其他服务一起工作,并且该组中的每个服务都使用一个数据库,我尝试不从这组低级别直接访问数据库服务。我只在高级服务中进行了所有数据库查询。 但在某些情况下很难。
也许这个问题用例子会更清楚:
trait DatabaseServiceComponent{
val databaseService: DatabaseService
trait DatabaseService{
def getSomeData(id: Int, tableName: String): List[String]
def getFriends(id: Int): List[Int]
}
}
trait DatabaseServiceComponentImpl extends DatabaseServiceComponent{
val databaseService: DatabaseService = new DatabaseServiceImpl
class DatabaseServiceImpl extends DatabaseService{
def getSomeData(id: Int, tableName: String): List[String] = ???
def getFriends(id: Int): List[Int] = ???
}
}
trait Scoring { this: DatabaseServiceComponent =>
def importantValues: Set[String]
val tableName: String
def getScore(id: Int): Double = databaseService.getSomeData(id, tableName).count(importantValues)
}
class Scoring1 extends Scoring{this: DatabaseServiceComponent =>
val tableName: String = "s1"
override def importantValues: Set[String] = Set("a", "b")
}
class Scoring2 extends Scoring{this: DatabaseServiceComponent =>
val tableName: String = "s2"
override def importantValues: Set[String] = Set("foo", "bar")
}
class Scoring3 extends Scoring{this: DatabaseServiceComponent =>
val tableName: String = "s3"
override def importantValues: Set[String] = Set("1", "2")
}
// How to implement this correctly?
trait Scoring2FriendsAverage {this: DatabaseServiceComponent =>
val scoring2: Scoring2
def getScore(id: Int):Double ={
val scores = databaseService.getFriends(id).map(scoring2.getScore)
scores.size / scores.sum
}
}
object FriendsScoringProcessor{
val scoring2Friends = new Scoring2FriendsAverage with DatabaseServiceComponentImpl{
val scoring2 = new Scoring2 with DatabaseServiceComponentImpl // I don't like that I have to mix the implementation of a service again
}
def printScores(id: Int): Unit = {
val score = scoring2Friends.getScore(id)
println(score)
}
}
我有一组评分,每个评分都使用一个数据库。我有一个 FriendsScoring,它使用其中一个使用数据库的评分。我希望能够仅将数据库实现混合到 FriendsScoring,并且不要在较低级别的服务中复制它。
我看到一个(可能)好的解决方案是通过隐式构造函数参数为低级服务提供实现。
看起来像蛋糕模式组件和服务的混合级别。
如果我们在服务层使用 Scoring
,那么它不应该出现在蛋糕模式层。
您可能希望将 Scoring
拆分为每个级别的两个嵌套特征,就像您对数据库所做的那样:
trait ScoringComponent {this: DatabaseServiceComponent =>
trait ScoringService {
def getScore(id: Int): Double =
databaseService.getSomeData(id, tableName).
count(importantValues)
}
}
然后你将能够在混合所需的依赖项后使用ScoringService
。