Kotlin教程笔记(51) - 改良设计模式 - 构建者模式

简介: Kotlin教程笔记(51) - 改良设计模式 - 构建者模式

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

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

Kotlin教程笔记(51) - 改良设计模式 - 构建者模式

imgKotlin - 改良设计模式 - 构建者模式

#一、前言

  • 构建者模式
    • 作用:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
    • 核心操作:私有化复杂对象(Product)的类构造器,设计并创建 Builder 类。

#二、使用构建者模式

  • 例子:组装电脑
  • 重点:多构造器、构建者模式

应用开发过程中,总会遇到创建复杂对象(Product)的情况,以组装电脑为例,从硬件到软件,需要配置的参数非常多,即构造器需要传入 n 个参数,于是我们可能会写出如下代码:

/**
 * 电脑类
 *
 * @author GitLqr
 */
class Computer(
    val mainboard: String, // 主板
    val cpu: String, // 处理器
    val ram: String, // 内存
    val battery: String, // 电源
    val gpu: String?, // 显卡
    val hardDisk: String?, // 硬盘
    val networkInterface: String?, // 网线接口
    val cdDriver: String?, // 光驱
    val os: String?, // 系统
    val chassis: String?, // 机箱
    val mouse: String?, // 鼠标
    val keyboard: String?, // 键盘
    val monitor: String? // 显示器
)

// 使用
val nbComputer = Computer(
    "超微X8QB6-F", "Intel Xeon E7-8870", "海盗船(CORSAIR) 复仇者LPX DDR4 2133 64GB 7000",
    "西门子豪华供电柜", "Leadtek/丽台Quadro Plex 7000", "WD_BLACK SN850 2T",
    "Intel/英特尔 万兆光纤网卡 EXPX9501AFXLR", "ThinkPad 43N3215 Blu-ray Burner Ultrabay",
    "Windows 11", "游戏悍将太极施洛华世奇", "RAPOO雷柏 3710 2.4G激光无线鼠标",
    "Optimus Maximus 多功能 概念式键盘", "Sharp/夏普 LB-1085 108英寸 FULL HD专业液晶显示器"
)

但是并不是所有的参数都是必须的,在 Java 中,我们一般会通过 重载构造器 来减少对象创建时需要传入的参数个数,在 Kotlin 中,重载构造器 就是定义次级构造器:

/**
 * 电脑类(重载构造器)
 *
 * @author GitLqr
 */
class Computer(
    val mainboard: String, // 主板
    val cpu: String, // 处理器
    val ram: String, // 内存
    val battery: String, // 电源
    val gpu: String?, // 显卡
    val hardDisk: String?, // 硬盘
    val networkInterface: String?, // 网线接口
    val cdDriver: String?, // 光驱
    val os: String?, // 系统
    val chassis: String?, // 机箱
    val mouse: String?, // 鼠标
    val keyboard: String?, // 键盘
    val monitor: String? // 显示器
) {
    // 次构造器需要调用主构造器传参
    constructor(mainboard: String, cpu: String, ram: String, battery: String) :
            this(mainboard, cpu, ram, battery, null, null, null, null, null, null, null, null, null)
}

// 使用
val simpleComputer = Computer("超微X8QB6-F", "Intel Xeon E7-8870", "海盗船(CORSAIR) 复仇者LPX DDR4 2133 64GB 7000", "西门子豪华供电柜")

但是 重载构造器 这种方案并不好,一旦重载的多了,代码就会变得很难维护,于是,在 Java 中,对于创建复杂对象这种情景,一般会使用 构建者模式 来处理,在使用 构建者模式 时需要遵循以下几点套路:

  • Product:私有化复杂对象的类构造器(确保使用者无法直接通过构造器创建实例)
  • Builder:
    • 必传参数 通过 构造器 传入
    • 可选参数 通过一系列 Setter 传入
    • 提供一个 build() 方法返回一个 Product 对象

下面我们就用 构建者模式 来改造上面的代码:

/**
 * 电脑类(构建者模式)
 *
 * @author GitLqr
 */
class Computer private constructor( // 私有化复杂对象的类构造器
    val mainboard: String, // 主板
    val cpu: String, // 处理器
    val ram: String, // 内存
    val battery: String, // 电源
    val gpu: String?, // 显卡
    val hardDisk: String?, // 硬盘
    val networkInterface: String? // 网线接口
    ...
) {
    // 【必传参数】通过 构造器 传入
    class Builder(val mainboard: String, val cpu: String, val ram: String, val battery: String) {
        var gpu: String? = null
        var hardDisk: String? = null
        var networkInterface: String? = null
        ...

        fun setGpu(gpu: String): Builder {
            this.gpu = gpu
            return this
        }

        fun setHardDisk(hardDisk: String): Builder {
            this.hardDisk = hardDisk
            return this
        }

        fun setNetworkInterface(networkInterface: String): Builder {
            this.networkInterface = networkInterface
            return this
        }

        ...

        // 别忘了,还要有一个 build() 方法,用来创建复杂对象并返回
        fun build(): Computer {
            return Computer(mainboard, cpu, ram, battery, gpu, hardDisk, networkInterface, ...)
        }
    }
}

// 使用
val computer =
    Computer.Builder("超微X8QB6-F", "Intel Xeon E7-8870", "海盗船(CORSAIR) 复仇者LPX DDR4 2133 64GB 7000", "西门子豪华供电柜")
        .setGpu("Leadtek/丽台Quadro Plex 7000")
        .setHardDisk("WD_BLACK SN850 2T")
        .setNetworkInterface("Intel/英特尔 万兆光纤网卡 EXPX9501AFXLR")
        .build()

总结一下 构建者模式 的优缺点:

  • 优点:
    • 结合 链式调用 设计,代码上更加美观
    • 对于可选参数的设置,更加语义化
  • 缺点:
    • 当可选参数比较多时,Builder 代码比较冗长
    • 在使用 Builder 时可能会忘记 build() 方法的调用
    • 在创建 Product 对象之前,必须先创建 Builder 对象,会增加额外的开销

#三、改良构建者模式

  • 例子:组装电脑
  • 重点:构建者模式本质上是模拟了具名的可选参数

Kotlin 作为更好的 Java,拥有更多现代语言的特性,具名可选参数 就是众多特性之一,我们完全可以使用这个特性来改良(或者说是取代)构建者模式。

Kotlin 的 具名可选参数 有以下特点:

  • 在具体化一个参数的取值时,可以通过带上它的参数名,而不是它在所有参数中的位置决定
  • 由于参数可以设置默认值,这允许我们可以只给出部分参数的取值,而不必是所有的参数

下面我们用 Kotlin 的 具名可选参数 来改造上面的代码:

/**
 * 电脑类(构建者模式)改良:带默认值的具名可选参数
 *
 * @author GitLqr
 */
class Computer(
    val mainboard: String, // 主板
    val cpu: String, // 处理器
    val ram: String, // 内存
    val battery: String, // 电源
    val gpu: String? = null, // 显卡
    val hardDisk: String? = null, // 硬盘
    val networkInterface: String? = null, // 网线接口
    val cdDriver: String? = null, // 光驱
    val os: String? = null, // 系统
    val chassis: String? = null, // 机箱
    val mouse: String? = null, // 鼠标
    val keyboard: String? = null, // 键盘
    val monitor: String? = null // 显示器
)

// 使用
val computer = Computer(
    "超微X8QB6-F", "Intel Xeon E7-8870", "海盗船(CORSAIR) 复仇者LPX DDR4 2133 64GB 7000", "西门子豪华供电柜",
    gpu = "Leadtek/丽台Quadro Plex 7000",
    os = "Windows 11",
    mouse = "RAPOO雷柏 3710 2.4G激光无线鼠标",
    keyboard = "Optimus Maximus 多功能 概念式键盘",
    monitor = "Sharp/夏普 LB-1085 108英寸 FULL HD专业液晶显示器"
)

总结一下 具名可选参数 的优点:

  • 代码简洁优雅,无论是 Product 的类结构,或者是创建一个 Product 实例
  • 创建 Product 实例时,显式指定参数名即可,无须按顺序传入
  • 所有参数均使用 val 声明,相比 Builder 中使用 var 更加安全

#四、对参数进行约束

构建者模式还有另一个作用,就是在 build() 方法中可以对参数进行约束,比如,如果一台电脑有指定操作系统(os),可是它没有硬盘(hardDisk),这显然是不对的,若使用构建者模式,则可以在 build() 方法中做如下条件约束:

/**
 * 构建者模式:在 build() 方法中对参数进行约束、校验
 *
 * @author GitLqr
 */
class Computer private constructor( ... ) {
    class Builder( ... ) {
        ...
        fun build(): Computer {
            if (os != null && hardDisk == null) {
                throw IllegalArgumentException("没有硬盘安装不了操作系统")
            }
            return Computer(...)
        }
    }
}

那么改用 具名可选参数 这种方案之后,如果需要给参数添加约束条件时该怎么办呢?可以在 init 代码块中进行约束条件判断,这时顺便介绍一下 Kotlin 提供的 require() 方法,相当于是 Java 中的 assert

/**
 * 具名可选参数:在 init{} 代码块中对参数进行约束、校验
 *
 * @author GitLqr
 */
class Computer(
    val mainboard: String, // 主板
    val cpu: String, // 处理器
    val ram: String, // 内存
    val battery: String, // 电源
    val gpu: String? = null, // 显卡
    val hardDisk: String? = null, // 硬盘
    val networkInterface: String? = null, // 网线接口
    val cdDriver: String? = null, // 光驱
    val os: String? = null, // 系统
    val chassis: String? = null, // 机箱
    val mouse: String? = null, // 鼠标
    val keyboard: String? = null, // 键盘
    val monitor: String? = null // 显示器
) {
    init {

        // if (os != null && hardDisk == null) {
        //     throw IllegalArgumentException("没有硬盘安装不了操作系统")
        // }

        require(!(os != null && hardDisk == null)) {
            "没有硬盘安装不了操作系统"
        }
    }
}

所以,综上所述,在 Kotlin 中,大可不必使用构建者模式~

《Effective Java》中是这样介绍构建者模式的:本质上 builder 模式模拟了具名的可选参数,就像 Ada 和 Python 中的一样。

相关文章
|
1天前
|
人工智能 自动驾驶 大数据
预告 | 阿里云邀您参加2024中国生成式AI大会上海站,马上报名
大会以“智能跃进 创造无限”为主题,设置主会场峰会、分会场研讨会及展览区,聚焦大模型、AI Infra等热点议题。阿里云智算集群产品解决方案负责人丛培岩将出席并发表《高性能智算集群设计思考与实践》主题演讲。观众报名现已开放。
|
17天前
|
存储 人工智能 弹性计算
阿里云弹性计算_加速计算专场精华概览 | 2024云栖大会回顾
2024年9月19-21日,2024云栖大会在杭州云栖小镇举行,阿里云智能集团资深技术专家、异构计算产品技术负责人王超等多位产品、技术专家,共同带来了题为《AI Infra的前沿技术与应用实践》的专场session。本次专场重点介绍了阿里云AI Infra 产品架构与技术能力,及用户如何使用阿里云灵骏产品进行AI大模型开发、训练和应用。围绕当下大模型训练和推理的技术难点,专家们分享了如何在阿里云上实现稳定、高效、经济的大模型训练,并通过多个客户案例展示了云上大模型训练的显著优势。
|
21天前
|
存储 人工智能 调度
阿里云吴结生:高性能计算持续创新,响应数据+AI时代的多元化负载需求
在数字化转型的大潮中,每家公司都在积极探索如何利用数据驱动业务增长,而AI技术的快速发展更是加速了这一进程。
|
12天前
|
并行计算 前端开发 物联网
全网首发!真·从0到1!万字长文带你入门Qwen2.5-Coder——介绍、体验、本地部署及简单微调
2024年11月12日,阿里云通义大模型团队正式开源通义千问代码模型全系列,包括6款Qwen2.5-Coder模型,每个规模包含Base和Instruct两个版本。其中32B尺寸的旗舰代码模型在多项基准评测中取得开源最佳成绩,成为全球最强开源代码模型,多项关键能力超越GPT-4o。Qwen2.5-Coder具备强大、多样和实用等优点,通过持续训练,结合源代码、文本代码混合数据及合成数据,显著提升了代码生成、推理和修复等核心任务的性能。此外,该模型还支持多种编程语言,并在人类偏好对齐方面表现出色。本文为周周的奇妙编程原创,阿里云社区首发,未经同意不得转载。
|
6天前
|
人工智能 自然语言处理 前端开发
100个降噪蓝牙耳机免费领,用通义灵码从 0 开始打造一个完整APP
打开手机,录制下你完成的代码效果,发布到你的社交媒体,前 100 个@玺哥超Carry、@通义灵码的粉丝,可以免费获得一个降噪蓝牙耳机。
2701 11
|
13天前
|
人工智能 自然语言处理 前端开发
用通义灵码,从 0 开始打造一个完整APP,无需编程经验就可以完成
通义灵码携手科技博主@玺哥超carry 打造全网第一个完整的、面向普通人的自然语言编程教程。完全使用 AI,再配合简单易懂的方法,只要你会打字,就能真正做出一个完整的应用。本教程完全免费,而且为大家准备了 100 个降噪蓝牙耳机,送给前 100 个完成的粉丝。获奖的方式非常简单,只要你跟着教程完成第一课的内容就能获得。
3472 9
|
11天前
|
人工智能 自然语言处理 前端开发
什么?!通义千问也可以在线开发应用了?!
阿里巴巴推出的通义千问,是一个超大规模语言模型,旨在高效处理信息和生成创意内容。它不仅能在创意文案、办公助理、学习助手等领域提供丰富交互体验,还支持定制化解决方案。近日,通义千问推出代码模式,基于Qwen2.5-Coder模型,用户即使不懂编程也能用自然语言生成应用,如个人简历、2048小游戏等。该模式通过预置模板和灵活的自定义选项,极大简化了应用开发过程,助力用户快速实现创意。
|
25天前
|
缓存 监控 Linux
Python 实时获取Linux服务器信息
Python 实时获取Linux服务器信息
|
7天前
|
人工智能 C++ iOS开发
ollama + qwen2.5-coder + VS Code + Continue 实现本地AI 辅助写代码
本文介绍在Apple M4 MacOS环境下搭建Ollama和qwen2.5-coder模型的过程。首先通过官网或Brew安装Ollama,然后下载qwen2.5-coder模型,可通过终端命令`ollama run qwen2.5-coder`启动模型进行测试。最后,在VS Code中安装Continue插件,并配置qwen2.5-coder模型用于代码开发辅助。
550 4
|
9天前
|
云安全 人工智能 自然语言处理