设计模式 - 装饰者模式,就该这样学!

目录

一、结构型模式

1.1、装饰者模式

1.1.1、概念

1.1.2、案例实现1

1.1.3、案例实现2

1.1.4、优缺点

1.1.5、使用场景


一、结构型模式


1.1、装饰者模式

1.1.1、概念

装饰者模式就是指在不改变现有对象结构的情况下,动态的给该对象增加一些职责(增加额外功能)的模式.

例如,在一个博客系统中,有时候你希望对方关注你后才能查看你的文章,或者是对方因为你的文章充值了 vip 后才可以查看你的文章,那么此时就可以使用装饰者模式,通过判断用户的权限,动态的给文章增加职责.

装饰者模式中的角色如下:

  • 抽象组件:定义一个抽象接口用来规范附加的对象.
  • 具体组件:实现抽象构件,将来会被添加一些职责).
  • 抽象装饰者:继承抽象构件 和 持有抽象构件的引用,可以通过 子类 扩展具体的构件.
  • 具体装饰者:继承抽象装饰,重写相关方法,给具体的构件对象添加附加责任.

1.1.2、案例实现1

需求:实现一个咖啡商店系统,咖啡可以动态的加糖加奶.

//抽象组件
interface Coffee {

    fun getDesc(): String
    fun getCost(): Double

}

//具体组件
class SimpleCoffee: Coffee {

    override fun getDesc(): String = "[ simple coffee ]"
    override fun getCost(): Double = 6.0

}

//抽象装饰者
abstract class CoffeeDecorator(
    private val coffee: Coffee
): Coffee {

    override fun getDesc(): String = coffee.getDesc()
    override fun getCost(): Double = coffee.getCost()

}

//具体装饰者
class MikeDecorator(
    coffee: Coffee
): CoffeeDecorator(coffee) {

    override fun getDesc(): String = "${coffee.getDesc()}, mike"
    override fun getCost(): Double = coffee.getCost() + 2.0

}

//具体装饰者
class SugarDecorator(
    coffee: Coffee
): CoffeeDecorator(coffee) {

    override fun getDesc(): String = "${coffee.getDesc()}, sugar"
    override fun getCost(): Double = coffee.getCost() + 1.0

}

fun main() {
    val simpleCoffee = SimpleCoffee()
    println("simpleCoffee:")
    println("desc: ${simpleCoffee.getDesc()}")
    println("cost: ${simpleCoffee.getCost()}")

    //加奶
    val mikeSimpleCoffee = MikeDecorator(simpleCoffee)
    println("mikeSimpleCoffee:")
    println("desc: ${mikeSimpleCoffee.getDesc()}")
    println("cost: ${mikeSimpleCoffee.getCost()}")

    //加糖
    val mikeSugarSimpleCoffee = SugarDecorator(mikeSimpleCoffee)
    println("mikeSugarSimpleCoffee:")
    println("desc: ${mikeSugarSimpleCoffee.getDesc()}")
    println("cost: ${mikeSugarSimpleCoffee.getCost()}")

}


执行结果如下:

1.1.3、案例实现2

a)BlogShow 接口定义了一个博客展示的基础功能,BaseBlogShow 进行了实现.

//抽象构建角色
interface BlogShow {

    fun getTitle(): String
    fun getContent(): String
    fun display()

}

//具体构建角色
data class BaseBlogShow(
    private val title: String,
    private val content: String
): BlogShow {

    override fun getTitle() = title

    override fun getContent() = content

    override fun display() {
        println("title: $title")
        println("content: $content")
    }

}

b)BlogShowDecorator 是抽象装饰者,定义了规范,并且持有 blogShow 对象(抽象构建对象).

FollowDecorator 和 VipDecorator 是具体装饰者,将来 BaseBlogShow 对象要进行动态扩展的时候,就可以将 BaseBlogShow 对象作为 具体装饰者的构造参数,动态扩展.

//抽象装饰角色
abstract class BlogShowDecorator(
    protected val blogShow: BlogShow
): BlogShow {

    override fun getTitle() = blogShow.getTitle()
    override fun getContent() = blogShow.getContent()
    override fun display() = blogShow.display()

}

//具体装饰角色
class FollowDecorator(
    blogShow: BlogShow
): BlogShowDecorator(blogShow) {

    override fun display() {
        val title = super.getTitle()
        val content = if(super.getContent().length > 60)
            super.getContent().substring(0, 60).plus("...")
        else
            super.getContent()

        println("title: $title")
        println("content: $content")
        println("> 关注作者,查看更多内容!")
    }

}

//具体装饰角色
class VipDecorator(
    blogShow: BlogShow
): BlogShowDecorator(blogShow) {

    override fun display() {
        val title = super.getTitle()
        val content = if(super.getContent().length > 60)
           super.getContent().substring(0, 60).plus("...")
        else
           super.getContent()

        println("title: $title")
        println("content: $content")
        println("> 充值 vip,查看更多内容!")
    }

}

c)使用如下

fun main() {
    //假设从数据库中拿到数据
    val dbBlog = BaseBlogShow("Kotlin (programming language)", "Kotlin is a cross-platform, statically typed, general-purpose high-level programming language with type inference. Kotlin is designed to interoperate fully")
    //这里根据用户的权限来给文章进行不同的内容
    //...
    //假设用户未关注对方,但是对方的文章设置了关注才能访问
    //那么此处添加 "关注装饰器"
    var blog = FollowDecorator(dbBlog)
    //最后给该用户展示
    blog.display()
}

运行结果如下 

1.1.4、优缺点

优点:

动态扩展:比继承具有更好的扩展性(继承时静态附加责任,装饰者时动态添加责任),可以在不修改原类的情况下,给对象添加责任.

缺点:

增加系统复杂度:装饰者比继承使用的类可能会少,但比继承使用的对象可能更多,更多的对象在程序排查错误的时候可能更复杂.

1.1.5、使用场景

1. 当不能采用继承的方式对程序进行扩展,比如存在大量的独立扩展,为了支持每一种组合产生大量子类,导致子类数目爆炸增长、或者是 类定位为 final 类型(不能继承).

2. 在不影响其他类的情况下,以动态的方式添加责任.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈亦康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值