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

简介: 本教程详细讲解Kotlin语法,适合希望深入了解Kotlin的开发者。对于快速学习Kotlin语法,推荐查看“简洁”系列教程。本文重点介绍了构建者模式在Kotlin中的应用与改良,包括如何使用具名可选参数简化复杂对象的创建过程,以及如何在初始化代码块中对参数进行约束和校验。

本系列学习教程笔记属于详细讲解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 中的一样。

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
1天前
|
设计模式 Java API
Kotlin教程笔记(50) - 改良设计模式 - 工厂模式
本教程详细解析了Kotlin语法,并针对设计模式进行了改良探讨,特别是工厂模式。通过Kotlin的单例模式、伴生对象、运算符重载及泛型等特性,展示了如何优化传统Java设计模式,使其更简洁高效。适合希望深入了解Kotlin特性的开发者。
10 3
|
1天前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
本系列教程笔记详细讲解了Kotlin语法,适合希望深入了解Kotlin的开发者。对于需要快速学习Kotlin的小伙伴,推荐查看“简洁”系列教程。本篇笔记重点介绍了Kotlin与Java混编的技巧,包括代码转换、类调用、ProGuard问题、Android库开发建议以及相互调用时的注意事项。
8 3
|
21天前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
1月前
|
设计模式 算法 安全
设计模式——模板模式
模板方法模式、钩子方法、Spring源码AbstractApplicationContext类用到的模板方法
设计模式——模板模式
|
28天前
|
设计模式 数据库连接 PHP
PHP中的设计模式:如何提高代码的可维护性与扩展性在软件开发领域,PHP 是一种广泛使用的服务器端脚本语言。随着项目规模的扩大和复杂性的增加,保持代码的可维护性和可扩展性变得越来越重要。本文将探讨 PHP 中的设计模式,并通过实例展示如何应用这些模式来提高代码质量。
设计模式是经过验证的解决软件设计问题的方法。它们不是具体的代码,而是一种编码和设计经验的总结。在PHP开发中,合理地使用设计模式可以显著提高代码的可维护性、复用性和扩展性。本文将介绍几种常见的设计模式,包括单例模式、工厂模式和观察者模式,并通过具体的例子展示如何在PHP项目中应用这些模式。
|
26天前
|
设计模式 Java Spring
spring源码设计模式分析-代理设计模式(二)
spring源码设计模式分析-代理设计模式(二)
|
3天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
12 0
|
24天前
|
设计模式 Java
Java设计模式-工厂方法模式(4)
Java设计模式-工厂方法模式(4)
|
2月前
|
设计模式
设计模式-单一职责模式
设计模式-单一职责模式
|
2月前
|
设计模式 XML 存储
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
文章详细介绍了工厂方法模式(Factory Method Pattern),这是一种创建型设计模式,用于将对象的创建过程委托给多个工厂子类中的某一个,以实现对象创建的封装和扩展性。文章通过日志记录器的实例,展示了工厂方法模式的结构、角色、时序图、代码实现、优点、缺点以及适用环境,并探讨了如何通过配置文件和Java反射机制实现工厂的动态创建。
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)