Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式

简介: Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式

本系列学习教程笔记属于详细讲解Kotlin语法的教程,需要快速学习Kotlin语法的小伙伴可以查看“简洁” 系列的教程

快速入门请阅读如下简洁教程:
Kotlin学习教程(一)
Kotlin学习教程(二)
Kotlin学习教程(三)
Kotlin学习教程(四)
Kotlin学习教程(五)
Kotlin学习教程(六)
Kotlin学习教程(七)
Kotlin学习教程(八)
Kotlin学习教程(九)
Kotlin学习教程(十)

Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式

imgKotlin - 改良设计模式 - 装饰者模式

#一、前言

  • 装饰者模式
    • 作用:在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。
    • 本质:该模式通过创建一个包装对象,来包裹真实的对象。
    • 核心操作:
      • 创建一个装饰类,包含一个被装饰类的实例
      • 装饰类重写所有被装饰类的方法
      • 在装饰类中对需要增强的功能进行扩展

#二、使用装饰者模式

  • 例子:枪支部件
  • 重点:装饰器类设计(实现被装饰类相同的接口,构造器接收被装饰类的接口实例对象)

像绝地求生这种大型射击游戏,里面的枪支系统是很复杂的,有很多种枪,而且几乎每种枪上都可以装配各种各样的部件,比如消声器、八倍镜之类的,部件的作用各不相同,有的可以增加火力,有的可以提高精确度,等等,现在我们来简单设计一下这个枪支系统,枪有很多种,所以需要定义一个接口来描述枪都有哪些能力,供后续扩展各种新枪:

/**
 * 枪支接口
 *
 * @author GitLqr
 */
interface Gun {
    /**
     * 攻击力
     */
    fun attack(): Float

    /**
     * 噪音
     */
    fun noise(): Float

    /**
     * 生产日期
     */
    fun prodDate(): String
}

/**
 * Ump9
 *
 * @author GitLqr
 */
class Ump9Gun : Gun {
    override fun attack() = 100f

    override fun noise() = 20f

    override fun prodDate() = "2020-02-18"
}

这里只实现了 Ump9 这个型号的枪,后续还可以根据需要扩展,现在来想想枪支部件怎么设计?在 Java 中,给一个类扩展行为有两种选择:

  • 设计一个继承它的子类
  • 使用装饰者模式对该类进行装饰

那么枪支部件合适用继承方式来设计吗?显然不合适,因为一个部件可以装配在不只一种枪上,所以继承这种方式排除。另一种方式,使用装饰者模式有一个很大的优势,在于符合“组合优于继承”的设计原则,我们知道,部件可以和任意枪组合,显示,使用装饰者模式来设计枪支部件是一个不错的选择:

/**
 * 枪支部件
 *
 * @author GitLqr
 */
abstract class GunPart(protected val gun: Gun) : Gun

/**
 * 消声器
 *
 * @author GitLqr
 */
class Muffler(gun: Gun) : GunPart(gun) {
    override fun attack() = gun.attack() - 5

    override fun noise() = 0f

    override fun prodDate() = gun.prodDate()
}

/**
 * 燃烧子弹
 *
 * @author GitLqr
 */
class FireBullet(gun: Gun) : GunPart(gun) {
    override fun attack() = gun.attack() + 200

    override fun noise() = gun.noise()

    override fun prodDate() = gun.prodDate()
}

程序设计时,装饰器(部件)会引用被装饰实例(枪),并实现被装饰实例的所有接口,然后在需要增强的接口方法中加入增强逻辑。因为枪支部件 GunPart 接收 Gun 类型构造参数,而且本身也是 Gun 接口的实现类,所以,可以让多种枪支部件 GunPart 嵌套修饰枪实例:

// 使用
var ump9: Gun = Ump9Gun()
println("装配前:ump9 攻击力 ${ump9.attack()},噪音 ${ump9.noise()}")
ump9 = Muffler(FireBullet(ump9)) // 装配了 燃烧子弹、消声器 的ump9
println("装配后:ump9 攻击力 ${ump9.attack()},噪音 ${ump9.noise()}")

// 输出
装配前:ump9 攻击力 100.0,噪音 20.0
装配后:ump9 攻击力 295.0,噪音 0.0

#三、改良装饰者模式

  • 例子:枪支部件
  • 重点:类委托(by 关键字)

在上面的例子中,装饰者模式可以很好的解决实例组合的情况,但是代码还是显得比较啰唆,因为需要重写所有的装饰对象方法,所以可能会存在大量样板代码。比如 FireBullet 只装饰增强 attack() 方法,而 noise()prodDate() 均不做修改,但还要是把这两个方法重写一遍。Kotlin 中有类委托特性,利用 by 关键字,将装饰类的所有方法委托给一个被装饰的类对象,然后只需覆写装饰的方法即可:

/**
 * 枪支部件
 *
 * @author GitLqr
 */
abstract class GunPart(protected val gun: Gun) : Gun by gun

/**
 * 消声器
 *
 * @author GitLqr
 */
class Muffler(gun: Gun) : GunPart(gun) {
    override fun attack() = gun.attack() - 5
    override fun noise() = 0f
}

/**
 * 燃烧子弹
 *
 * @author GitLqr
 */
class FireBullet(gun: Gun) : GunPart(gun) {
    override fun attack() = gun.attack() + 200
}

可以看到,使用类委托之后,装饰类 FireBullet 中的样板代码不用重写了,从而减少了代码量。

目录
相关文章
|
5天前
|
Kotlin 索引
Kotlin教程笔记(22) -常见高阶函数
Kotlin教程笔记(22) -常见高阶函数
|
5天前
|
Kotlin
Kotlin教程笔记(21) -高阶函数与函数引用
Kotlin教程笔记(21) -高阶函数与函数引用
|
5天前
|
Kotlin
Kotlin教程笔记(20) - 枚举与密封类
Kotlin教程笔记(20) - 枚举与密封类
14 3
|
5天前
|
安全 Kotlin
Kotlin教程笔记(23) -作用域函数
Kotlin教程笔记(23) -作用域函数
|
安全 Java Android开发
Kotlin 设计模式解析之单例
### 单例模式介绍 单例模式是一个比较简单的设计模式,同时也是挺有意思的一个模式,虽然看起来简单,但是可以玩出各种花样。比如 Java 当中的懒饿汉式单例等。 #### 什么是单例 单例模式的定义: > Ensure a class only has one instance, and provide a global point of access to it. 简单来说
1776 0
|
30天前
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
19 1
|
2月前
|
Android开发 开发者 Kotlin
告别AsyncTask:一招教你用Kotlin协程重构Android应用,流畅度飙升的秘密武器
【9月更文挑战第13天】随着Android应用复杂度的增加,有效管理异步任务成为关键。Kotlin协程提供了一种优雅的并发操作处理方式,使异步编程更简单直观。本文通过具体示例介绍如何使用Kotlin协程优化Android应用性能,包括网络数据加载和UI更新。首先需在`build.gradle`中添加coroutines依赖。接着,通过定义挂起函数执行网络请求,并在`ViewModel`中使用`viewModelScope`启动协程,结合`Dispatchers.Main`更新UI,避免内存泄漏。使用协程不仅简化代码,还提升了程序健壮性。
75 1
|
3月前
|
调度 Android开发 开发者
【颠覆传统!】Kotlin协程魔法:解锁Android应用极速体验,带你领略多线程优化的无限魅力!
【8月更文挑战第12天】多线程对现代Android应用至关重要,能显著提升性能与体验。本文探讨Kotlin中的高效多线程实践。首先,理解主线程(UI线程)的角色,避免阻塞它。Kotlin协程作为轻量级线程,简化异步编程。示例展示了如何使用`kotlinx.coroutines`库创建协程,执行后台任务而不影响UI。此外,通过协程与Retrofit结合,实现了网络数据的异步加载,并安全地更新UI。协程不仅提高代码可读性,还能确保程序高效运行,不阻塞主线程,是构建高性能Android应用的关键。
59 4
|
4月前
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
**Kotlin中的`by lazy`和`lateinit`都是延迟初始化技术。`by lazy`用于只读属性,线程安全,首次访问时初始化;`lateinit`用于可变属性,需手动初始化,非线程安全。`by lazy`支持线程安全模式选择,而`lateinit`适用于构造函数后初始化。选择依赖于属性特性和使用场景。**
150 5
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
|
4月前
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin中常见作用域函数
**Kotlin作用域函数概览**: `let`, `run`, `with`, `apply`, `also`. `let`安全调用并返回结果; `run`在上下文中执行代码并返回结果; `with`执行代码块,返回结果; `apply`配置对象后返回自身; `also`附加操作后返回自身
58 8