代数数据类型 ADT
组合类型。例如,一个类型由其他类型组合而成。常见的代数类型是 和(sum)类型、积(product)类型。ADT是类型安全的。
积类型
ADT中,积类型的表现形式与乘法非常相似,可以理解为一种组合。
和类型
比如枚举,和类型是类型安全的,因为它是一个闭环,如上节的Day枚举。也是一种OR关系,要么是SUN,要么是MON,不能同时拥有两种类型。
可以利用密闭类对枚举进行改造
sealed class Shape {
class Circle(val radius: Double) : Shape()
class Rectangle(val width: Double, val heigit: Double) : Shape()
class Triangle(val base: Double, val heigit: Double) : Shape()
}
模式匹配
//常量模式
fun constantPattern(a: Int) = when (a) {
1 -> "is 1"
2 -> "is 2"
else -> "other"
}
//类型模式
fun getArea(shape: Shape): Double = when (shape) {
is Shape.Circle -> Math.PI * shape.radius * shape.radius
is Shape.Rectangle -> shape.width * shape.heigit
is Shape.Triangle -> shape.base * shape.heigit / 2.0
}
//逻辑表达式模式
fun logicPattern(a: Int) = when (a) {
in 2..11 -> a.toString()
else -> "other $a"
}
模式匹配中的模式就是表达式,模式匹配的要匹配的就是表达式。模式匹配的核心就是结构,也就是反向构造表达式——给定一个复杂的数据结构,然后将之前用来构成该复杂的参数抽取出来。
在Kotlin中采用when进行模式匹配可以简化大部分问题。
实现模式匹配的技术主要有6种,Kotlin采用3种,分别是类型测试 / 类型转换、面向对象的分解、访问设计模式
类型测试 / 类型转换:判断所给的值是何种类型 is 关键字
面向对象的分解:在父类中定义一系列测试方法,然后在子类中实现这些方法
访问设计模式:表示一个作用于某个对象结构中的各元素的操作,可以在不改变各元素类的前提下定义作用域这些元素的新操作
小案例
/*
开发一个与优惠券相关的业务
优惠券有多种类型,如现金券、礼品券及折扣券
现金券能够实现“满多少金额减多少金额”,礼品券能够通过券上表明的礼品来兑换相应礼物,折扣券表示用户能够享受多少折扣
用户可以领取优惠券,领取之后也可以使用优惠
优惠券的使用时间是可以指定在某个特定时间段内
如果优惠券在指定的时间内没有使用的话就会过期
*/
//优惠券,密闭类改造
sealed class Coupon(
// val id: Long,
// val type: String,
// //券类型未代金券的时候使用,满足leastCost减少reduceCost
// val leastCost: Long?,
// val reduceCost: Long?,
// //券类型未折扣券的时候使用
// val discount: Int?,
// //券类型为礼品券的时候使用
// val gift: String?
) {
//优惠券的类型
companion object {
final val CashType = "Cash"
final val DiscountType = "DISCOUNT"
final val GiftType = "GIFT"
final val NotFetched = 1 //未领取
final val Fetched = 2 //已领取但未使用
final val Used = 3 //已使用
final val Expired = 4 //已过期
final val UnAvilable = 5 //已失效
}
//ADT思想重新抽象
class CashCoupon(
val id: Long,
val type: String,
//券类型未代金券的时候使用,满足leastCost减少reduceCost
val leastCost: Long?,
val reduceCost: Long?
) : Coupon()
class DiscountCoupon(
val id: Long,
val type: String,
//券类型未折扣券的时候使用
val discount: Int?
) : Coupon()
class GiftCoupon(
val id: Long,
val type: String,
//券类型为礼品券的时候使用
val gift: String?
) : Coupon()
//根据用户信息和优惠券信息,判断某个用户是否领取了优惠券
fun fetched(coupon: Coupon, user: User): Boolean {
return false
}
//根据用户信息和优惠券信息,判断优惠券是否已被该用户使用
fun isUsed(coupon: Coupon, user: User): Boolean {
return false
}
//判断优惠券是否过期
fun isExpired(coupon: Coupon): Boolean {
return false
}
//判断优惠券是否已经失效
fun isUnAciable(coupon: Coupon): Boolean {
return false
}
//判断优惠券状态
fun getCouponStatus(coupon: Coupon, user: User): Int = when {
isUnAciable(coupon) -> Coupon.UnAvilable //无效
isExpired(coupon) -> Coupon.Expired //过期
isUsed(coupon, user) -> Coupon.Used //被使用
fetched(coupon, user) -> Coupon.Fetched //已领取
else -> Coupon.NotFetched //未领取
}
fun showStatus(coupon: Coupon, user: User) = when (getCouponStatus(coupon, user)) {
Coupon.UnAvilable -> showUnAvilable() //已失效
Coupon.Expired -> showExpired() //已过期
Coupon.Used -> showUsed() //已使用
Coupon.Fetched -> showFetched() //已领取但未使用
else -> showNotFetched() //未领取
}
fun showNotFetched() {}
fun showFetched() {}
fun showUsed() {}
fun showExpired() {}
fun showUnAvilable() {}
}
class User()
更高层次抽象
//1、对优惠券的状态进行抽象,将其变成ADT
//sealed class CouponStatus {
// object StatusNotFetched : CouponStatus()
// object StatusFetched : CouponStatus()
// object StatusUsed : CouponStatus()
// object StatusExpired : CouponStatus()
// object StatusUnAcilable : CouponStatus()
//}
//2、将优惠券与CouponStatus进行组合
//sealed class CouponStatus {
// data class StatusNotFetched(val coupon: Coupon) : CouponStatus()
// data class StatusFetched(val coupon: Coupon) : CouponStatus()
// data class StatusUsed(val coupon: Coupon) : CouponStatus()
// data class StatusExpired(val coupon: Coupon) : CouponStatus()
// data class StatusUnAcilable(val coupon: Coupon) : CouponStatus()
//}
//3、已使用和已领取,需要user
sealed class CouponStatus {
data class StatusNotFetched(val coupon: Coupon) : CouponStatus()
data class StatusFetched(val coupon: Coupon, val user: User) : CouponStatus()
data class StatusUsed(val coupon: Coupon, val user: User) : CouponStatus()
data class StatusExpired(val coupon: Coupon) : CouponStatus()
data class StatusUnAvilable(val coupon: Coupon) : CouponStatus()
}
//4、不需要在每一次判断的时候去调用getCouponStatus方法,该方法只需在CouponStatus被实例化的时候调用一下,改造为getCouponStatus2
fun getCouponStatus2(coupon: Coupon, user: User): CouponStatus = when {
isUnAciable(coupon) -> CouponStatus.StatusUnAvilable(coupon) //无效
isExpired(coupon) -> CouponStatus.StatusExpired(coupon) //过期
isUsed(coupon, user) -> CouponStatus.StatusUsed(coupon, user) //被使用
fetched(coupon, user) -> CouponStatus.StatusFetched(coupon, user) //已领取
else -> CouponStatus.StatusNotFetched(coupon) //未领取
}
//5、改造showStatus
fun showStatus2(coupon: Coupon, user: User) = when (getCouponStatus2(coupon, user)) {
is CouponStatus.StatusUnAvilable -> showUnAvilable() //已失效
is CouponStatus.StatusExpired -> showExpired() //已过期
is CouponStatus.StatusUsed -> showUsed() //已使用
is CouponStatus.StatusFetched -> showFetched() //已领取但未使用
is CouponStatus.StatusNotFetched -> showNotFetched() //未领取
}