设计模式-装饰模式

装饰模式

1.装饰模式的定义

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。

装饰模式的通用类图如图所示:
在这里插入图片描述

1.1 使用场景

我们先不从定义或是类图中扯那么多没用的,先举个?。
接口:

interface People {
    /**
     * 灵魂
     */
    fun mind()

    /**
     * 肉体
     */
    fun body()
}

学生类:

class Student:People {
    override fun mind() {
        println("一个学生")
    }

    override fun body() {
        println("穿上校服")
    }
}

客户端:

class ClientActivity : Activity() {

    fun init() {
     //一个学生
        val student: People = Student()
        student.body()
        student.mind()
    }

}

输出结果:

在这里插入图片描述

这样看起来,还并没有什么不妥。
如果我们给一个场景呢?

场景一:描述10个灵魂和身体不同的学生。(可以看作10种不同的情况或场景)

你会选择继承,扩展子类的方式去实现吗?

  • 不会。为什么?扩展的子类太多了,尤其是变化太多的时候。

那为什么我们选择了装饰模式呢?

  • 10种变化,在最坏的情况下,我们也是会有10个装饰类的扩展。但是很多时候,10种变化,可能是几种不同的排列组合造成的结果,也许只需要4个装饰类呢?
  • 装饰类并不影响被装饰的那个类,意味着灵活性非常高,等会可以看看我们写的代码。
场景二: Student类或许是一个final类,或是系统源码final类(人为不可修改)的。

你会选择继承,扩展子类的方式去实现吗?

  • 不会,因为final限制了我们的子类扩展,不允许这样做。

但是我们可以选择代理模式吗?

  • 当然可以。 但是还是得看更具体的场景使用,看自己的选择。
  • 代理模式,更看重的是对被代理对象的一种控制
  • 而装饰模式,更看重的是添加或增强被装饰对象的功能
场景三:两个Student对象,同一个方法实现的效果不同
  • 这种场景下,无论是同一个对象,还是多个对象,实现效果不同,都挺适合使用装饰模式的。就算你想用其他方式实现,我也不反对,就是那么圆滑

1.2 代码实现

让我们来实现场景1下的代码:
这里就不写10种变化了,看你自己扩展吧。
接口:

interface People {
    /**
     * 灵魂
     */
    fun mind()

    /**
     * 肉体
     */
    fun body()
}

学生类:

class Student:People {
    override fun mind() {
        println("一个学生")
    }

    override fun body() {
        println("穿上校服")
    }
}

抽象装饰类:

 abstract class Decorator:People{
    var people:People?=null
}

具体装饰类:

/**
 * 内心强大的装饰类
 */
class StrongStudent:Decorator() {

    override fun mind() {
        println("内心强大")
        this.people?.mind()
    }

    override fun body() {
        this.people?.body()
    }

}

/**
 * 生病穿多件外套的装饰类
 */
class IllStudent: Decorator() {

    override fun mind() {
        this.people?.mind()

    }

    override fun body() {
        this.people?.body()
        println("穿上校外套")
    }

}

客户端:

class ClientActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        init()
    }

    fun init() {
        //一个学生
        val student: People = Student()
        student.body()
        student.mind()

        println("===============")

        //一个内心强大的学生
        val strongStudent:Decorator = StrongStudent();
        strongStudent.people = student
        strongStudent.body()
        strongStudent.mind()

        println("===============")

         //一个生病的学生
        val illStudent:Decorator= IllStudent();
        illStudent.people = student
        illStudent.body()
        illStudent.mind()

        println("===============")

        //一个生了病但内心强大的学生
        illStudent.people = strongStudent
        illStudent.body()
        illStudent.mind()

    }

}

输出结果
在这里插入图片描述

1.3 总结

经典实例:

Java的IO流(FileInputStream和BufferInputStream等等)

优点

  • 灵活性高

缺点

  • 灵活性高。也正是灵活性太高,会导致一些问题。
    (1) 比如,让组合逻辑暴露了出来,没有进行封装。至于到底封装不封装,看自己选择。
    (2)装饰类大同小异,难以区分使用。好比一双休闲鞋和一双运动鞋,内行人知道在什么场合使用,但外行人只知道它们都是鞋。好比参与了需求分析的开发,知道如何使用。但是,后面维护的开发是懵的,需要付出一定的代价去理解。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值