重学Kotlin——代数数据类型和模型匹配

本文探讨了代数数据类型(ADT)的概念,包括积类型和和类型,以及它们在Kotlin中的应用。通过具体案例展示了如何使用ADT进行优惠券业务的设计,包括现金券、礼品券和折扣券的抽象表示,以及利用模式匹配进行状态判断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代数数据类型 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()                //未领取
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值