如何避免在Scala中复制对象类中绑定的类型



是的,我已经检查了标题非常相似的问题,但给出的答案对我没有帮助,因为我是Scala的新手,很难理解它。

我正在编写一些函数,检查卡片列表并根据列表结果返回分数。从技术上讲,它检查一组卡片的列表,但为了这个问题的目的,我正在简化代码。

现在,我希望这些函数可以扩展到不同类型的评分。例如,如果所有的牌都是红心大战,那么我们可以给它们1分。然而,在另一个规则集中,它可能会给出3分。

我有一个分数包装器,可以翻译成最终分数。这意味着一种类型的分数可能会转化为与另一种类型分数不同的最终分数。这里的目的是让你可以自定义得分,并以稍微不同的方式玩纸牌游戏。

您将在下面的示例代码中看到,但我的方法声明中有很多重复,即必须一遍又一遍地编写[T <: HandPoints[T]]

所有的def方法都是在object中编写的,所以我无法将类型参数添加到类中。

我想可能有一个巧妙的解决方案可以在类外提取这些方法,但我希望检查卡的方法不要重复,所以在object中静态声明它们对我来说很有意义

这是HandPoints的特点:

trait HandPoints[T] {
def toHandScore: HandScore
def zero: T
def add(that: T): T
}
case class RegularPoint(points: Int) extends HandPoints[RegularPoint] {
override def toHandScore: HandScore = HandScore(points)
override def zero: RegularPoint = RegularPoint(0)
override def add(that: RegularPoint): RegularPoint = RegularPoint(points + that.points)
}
case class DoublingPoints(points: Int) extends HandPoints[DoublingPoints] {
override def toHandScore: HandScore = HandScore(points*2)
override def zero: DoublingPoints = DoublingPoints(0)
override def add(that: DoublingPoints): DoublingPoints = DoublingPoints(points + that.points)
}
case class HandScore(score: Int) {
}

以下是我编写的评估卡片的功能


trait Card {
def getValue: Int
def getSuit: String
}

def scored[T <: HandPoints[T]](score: T)(boolean: Boolean): T = {
if (boolean) score else score.zero
}
def isAllEvens[T <: HandPoints[T]](score: T)(cards: List[Card]): T = {
scored(score) {
cards.forall(_.getValue % 2 == 0)
}
}
def isAllReds[T <: HandPoints[T]](score: T)(cards: List[Card]): T = {
scored(score) {
cards.forall(List("HEARTS", "DIAMONDS").contains(_))
}
}
def isAllNoDuplicates[T <: HandPoints[T]](score: T)(cards: List[Card]): T = {
scored(score) {
cards.distinct == cards
}
}

val regularGameCriteria: List[List[Card] => RegularPoint] = List(
isAllEvens(RegularPoint(1)),
isAllReds(RegularPoint(3)),
isAllNoDuplicates(RegularPoint(5))
)

val beginnerGameCriteria: List[List[Card] => RegularPoint] = List(
isAllEvens(RegularPoint(1)),
isAllReds(RegularPoint(1)),
isAllNoDuplicates(RegularPoint(1))
)
val superGameCriteria: List[List[Card] => DoublingPoints] = List(
isAllEvens(DoublingPoints(1)),
isAllReds(DoublingPoints(3)),
isAllNoDuplicates(DoublingPoints(5))
)

def countScore[T <: HandPoints[T]](scoreList: List[List[Card] => T])(melds: List[Card]): T = {
scoreList.map(f => f(melds)).reduce((a, b) => a.add(b))
}
def regularGameScore(cards: List[Card]): RegularPoint = {
countScore(regularGameCriteria)(cards)
}
def beginnerGameScore(cards: List[Card]): RegularPoint = {
countScore(beginnerGameCriteria)(cards)
}
def superGameScore(cards: List[Card]): DoublingPoints = {
countScore(superGameCriteria)(cards)
}

首先,您可以了解如何用特殊多态性(类型类(替换F-有界多态性:

https://tpolecat.github.io/2015/04/29/f-bounds.html

其次,不同方法中的边界[T <: HandPoints[T]]实际上不是代码重复。不同的CCD_ 6在不同的方法中是不同的类型参数。你只是用同一封信打电话给他们。一个类型参数的边界不会限制另一个类型的参数。

我很好奇为什么你会考虑用不同的方法来复制代码[T <: HandPoints[T]],而不是(score: T)(cards: List[Card])。我想是因为大多数人考虑术语,认为类型不那么重要。

第三,你应该开始探索OOP(或带有类型类或它们的一些组合的FP(,即将你的方法组织成具有一些行为的类/对象(或类型类(。现在,一堆(静态(方法看起来像过程编程。

例如,首先我们可以引入两个类HandPointsHandlerCriteria(您可以选择更好的名称(:

case class HandScore(score: Int)
trait HandPoints[T] {
def toHandScore: HandScore
def zero: T
def add(that: T): T
}
case class RegularPoint(points: Int) extends HandPoints[RegularPoint] {
override def toHandScore: HandScore = HandScore(points)
override def zero: RegularPoint = RegularPoint(0)
override def add(that: RegularPoint): RegularPoint = RegularPoint(points + that.points)
}
case class DoublingPoints(points: Int) extends HandPoints[DoublingPoints] {
override def toHandScore: HandScore = HandScore(points*2)
override def zero: DoublingPoints = DoublingPoints(0)
override def add(that: DoublingPoints): DoublingPoints = DoublingPoints(points + that.points)
}
trait Card {
def getValue: Int
def getSuit: String
}
// new class
class HandPointsHandler[T <: HandPoints[T]] {
def scored(score: T)(boolean: Boolean): T =
if (boolean) score else score.zero
def isAllEvens(score: T)(cards: List[Card]): T =
scored(score) {
cards.forall(_.getValue % 2 == 0)
}
def isAllReds(score: T)(cards: List[Card]): T =
scored(score) {
cards.forall(List("HEARTS", "DIAMONDS").contains)
}
def isAllNoDuplicates(score: T)(cards: List[Card]): T =
scored(score) {
cards.distinct == cards
}
def countScore(scoreList: List[List[Card] => T])(melds: List[Card]): T =
scoreList.map(_.apply(melds)).reduce(_ add _)
}
// new class
class Criteria[T <: HandPoints[T]](handler: HandPointsHandler[T], points: List[T]) {
val gameCriteria: List[List[Card] => T] = {
List(
handler.isAllEvens _,
handler.isAllReds _,
handler.isAllNoDuplicates _
).zip(points).map { case (f, point) => f(point) }
}
}
val points135 = List(1, 3, 5)
val points111 = List(1, 1, 1)
val regularPointsHandler = new HandPointsHandler[RegularPoint]
val regularGameCriteria: List[List[Card] => RegularPoint] =
new Criteria[RegularPoint](regularPointsHandler, points135.map(RegularPoint)).gameCriteria
val beginnerGameCriteria: List[List[Card] => RegularPoint] =
new Criteria[RegularPoint](regularPointsHandler, points111.map(RegularPoint)).gameCriteria
val doublingPointsHandler = new HandPointsHandler[DoublingPoints]
val superGameCriteria: List[List[Card] => DoublingPoints] =
new Criteria[DoublingPoints](doublingPointsHandler, points135.map(DoublingPoints)).gameCriteria
def regularGameScore(cards: List[Card]): RegularPoint =
regularPointsHandler.countScore(regularGameCriteria)(cards)
def beginnerGameScore(cards: List[Card]): RegularPoint =
regularPointsHandler.countScore(beginnerGameCriteria)(cards)
def superGameScore(cards: List[Card]): DoublingPoints =
doublingPointsHandler.countScore(superGameCriteria)(cards)

相关内容

  • 没有找到相关文章

最新更新