假设我有一个可能的列表,信用卡
val availableCreditsCard = List(MasterCardCreditCard, VisaCreditCard)
这两个类都扩展了一个称为CreditCard
的特征
现在,我想创建一个名为isValid
的方法,该方法接受特征CreditCard
类似的东西:
def isValid(creditCard: CreditCard): Boolean = {
creditCard match {
case t: MasterCardCreditCard => MasterCardCreditCardPayment.isValid(t)
case s: VisaCreditCard => VisaCreditCardPayment.isValid(s)
}
}
MasterCardCreditCardPayment 和 VisaCreditCardPayment 都扩展了一个名为CreditCardPayment
的特征。
现在,我的问题是,如果我想添加一个新的可能的CreditCard(Amex)和他自己的CreditCardPayment(AmexCreditCardPayment),但只需更改列表availableCreditsCard
并且不触碰< emValid方法中的em> match / case ?
是否可以根据列表availableCreditsCard
来动态创建此匹配项/案例?
编辑
这是CreditCardPayment特性。
trait CreditCardPayment[CreditCard] {
def isValid(creditCard: CreditCard): Boolean
def checkCVV(creditCard: CreditCard): Boolean
}
以及VisaCreditCardPayment
object VisaCreditCardPayment extends CreditCardPayment[VisaCreditCard] {
override def isValid(creditCard: VisaCreditCard): Boolean = {
val listValidCreditCard = loadFile()
listValidCreditCard.contains(creditCard)
}
//Implemented because it the trait, not necessary
override def checkCVV(creditCard: VisaCreditCard): Boolean = {
val listCreditCard = loadFile()
val cvvToCheck = creditCard.cvv
listCreditCard.exists(_.cvv == cvvToCheck)
}
}
现在,您的建议是在isValid
方法内使用case t => CreditCardPayment.isValid(t)
。由于CreditCardPayment
是一个特质:(
答案 0 :(得分:5)
如果您希望它是“动态的”,则只需使用继承,而不要“在侧面”实现它:
sealed trait CreditCard {
def isValid: Boolean
}
class MasterCard extends CreditCard {
def isValid = MasterCardCreditCardPayment.isValid(this)
}
class Visa extends CreditCard {
def isValid = VisaCreditCardPayment.isValid(this)
}
现在,您只需执行def isValid(c: CreditCard) = c.isValid
,无需任何match
语句即可保持同步。
添加美国运通卡时:
class Amex extends CreditCard {
def isValid = AmexCreditCardPayment.isValid(this)
}
isValid(amex)
可以正常工作,不需要更新任何内容。
答案 1 :(得分:1)
补充Dima的答案。既然如此,您始终希望将isValid
逻辑委派给适当的Payment
。我将向您展示两种不重新定义每个子类中方法的方法。
一种使用 F界多态性的方法,该方法将需要为每个子类提供相当的样板代码,并且它不是完全
第二个使用 typeclasses ,这会更
有关 F绑定与 Typeclasses 的更详细的讨论,请阅读this文章。
sealed trait CreditCardPayment[CC <: CreditCard[CC]] {
def isValid(creditCard: CC): Boolean
def checkCVV(creditCard: CC): Boolean
}
object VisaCreditCardPayment extends CreditCardPayment[VisaCreditCard] {
private final val validCreditCards: List[VisaCreditCard] = ???
override def isValid(creditCard: VisaCreditCard): Boolean =
validCreditCards.contains(creditCard)
override def checkCVV(creditCard: VisaCreditCard): Boolean =
validCreditCards.exists(_.cvv == creditCard.cvv)
}
object MasterCreditCardPayment extends CreditCardPayment[MasterCreditCard] {
private final val validCreditCards: List[MasterCreditCard] = ???
override def isValid(creditCard: MasterCreditCard): Boolean =
validCreditCards.contains(creditCard)
override def checkCVV(creditCard: MasterCreditCard): Boolean =
validCreditCards.exists(_.cvv == creditCard.cvv)
}
sealed trait CreditCard[CC <: CreditCard[CC]] { self: CC =>
def paymentMethod: CreditCardPayment[CC]
def cvv: String
final def isValid: Boolean =
paymentMethod.isValid(this)
}
final class VisaCreditCard (override val cvv: String) extends CreditCard[VisaCreditCard] {
override final val paymentMethod: CreditCardPayment[VisaCreditCard] = VisaCreditCardPayment
}
final class MasterCreditCard (override val cvv: String) extends CreditCard[MasterCreditCard] {
override final val paymentMethod: CreditCardPayment[MasterCreditCard] = MasterCreditCardPayment
}
sealed trait CreditCardPayment[CC <: CreditCard] {
def isValid(creditCard: CC): Boolean
def checkCVV(creditCard: CC): Boolean
}
sealed trait CreditCard {
def cvv: String
}
// Provides the 'isValid' & 'checkCVV' extension methods to any CredictCard.
implicit class CreditCardOps[CC <: CreditCard](val self: CC) extends AnyVal {
def isValid(implicit payment: CreditCardPayment[CC]): Boolean =
payment.isValid(self)
def checkCVV(implicit payment: CreditCardPayment[CC]): Boolean =
payment.checkCVV(self)
}
final class VisaCreditCard (override val cvv: String) extends CreditCard
object VisaCreditCard {
final implicit val VisaCreditCardPayment: CreditCardPayment[VisaCreditCard] = new CreditCardPayment[VisaCreditCard] {
final val validCreditCards: List[VisaCreditCard] = ???
override def isValid(creditCard: VisaCreditCard): Boolean =
validCreditCards.contains(creditCard)
override def checkCVV(creditCard: VisaCreditCard): Boolean =
validCreditCards.exists(_.cvv == creditCard.cvv)
}
}
final class MasterCreditCard (override val cvv: String) extends CreditCard
object MasterCreditCard {
final implicit val MasterCreditCardPayment: CreditCardPayment[MasterCreditCard] = new CreditCardPayment[MasterCreditCard] {
final val validCreditCards: List[MasterCreditCard] = ???
override def isValid(creditCard: MasterCreditCard): Boolean =
validCreditCards.contains(creditCard)
override def checkCVV(creditCard: MasterCreditCard): Boolean =
validCreditCards.exists(_.cvv == creditCard.cvv)
}
}
使用 typeclass 方法,您还可以将isValid
的{{1}}方法定义为函数。
(通过这种方式,您无需定义和导入CreditCards
隐式/值类)。
CreditCardOps