一个标准的Builder模式写法示例

文章目录

  • User的构建
  • 子属性的Builder实现
    • Address类
    • Company的Builder
    • Contact的Builder
    • Education的Builder
  • 使用举例
  • 好处

本文以一个例子介绍了 Builder 模式的标准写法。
比如,有一个复杂的对象User,其中的属性也包括几个对象Address、Contact、Company、List。在构建这种对象时,使用Builder模式该如何实现呢?

User的构建

class User private constructor(
    firstName: String?,
    middleName: String?, // optional
    lastName: String?,
    address: Address?,
    contact: Contact?, // optional
    company: Company?, // optional
    educations: List<Education>,
) {
    val firstName: String
    val middleName: String? // optional
    val lastName: String
    val address: Address
    val contact: Contact? // optional
    val company: Company? // optional
    val educations: List<Education>

    init {
        if (firstName.isNullOrBlank())
            throw IllegalArgumentException("First name is required")

        if (lastName.isNullOrBlank())
            throw IllegalArgumentException("Last name is required")

        if (address == null)
            throw IllegalArgumentException("Address is required")

        if (educations.isEmpty())
            throw IllegalArgumentException("Education list is required")

        this.firstName = firstName
        this.middleName = middleName
        this.lastName = lastName
        this.address = address
        this.contact = contact
        this.company = company
        this.educations = educations
    }

    class Builder {
        private var firstName: String? = null
        private var middleName: String? = null // optional
        private var lastName: String? = null
        private var address: Address? = null
        private var contact: Contact? = null // optional
        private var company: Company? = null // optional
        private val educations = mutableListOf<Education>()

        fun setFirstName(firstName: String): Builder {
            this.firstName = firstName
            return this
        }

        // OR

        fun setMiddleName(middleName: String) = apply {
            this.middleName = middleName
        }

        fun setLastName(lastName: String) = apply {
            this.lastName = lastName
        }

        fun setAddress(address: Address) = apply {
            this.address = address
        }

        fun setContact(contact: Contact) = apply {
            this.contact = contact
        }

        fun setCompany(company: Company) = apply {
            this.company = company
        }

        fun addEducation(education: Education) = apply {
            this.educations.add(education)
        }

        fun addEducation(educations: List<Education>) = apply {
            this.educations.addAll(educations)
        }

        fun setEducations(educations: List<Education>) = apply {
            this.educations.clear()
            this.educations.addAll(educations)
        }

        fun build(): User {
            return User(
                firstName,
                middleName,
                lastName,
                address,
                contact,
                company,
                educations
            )
        }
    }
}

子属性的Builder实现

其他子属性也是同理

Address类

class Address(
    line1: String?,
    line2: String?,
    city: String?,
    state: String?,
    country: String?,
    pinCode: Int?
) {

    val line1: String
    val line2: String?
    val city: String
    val state: String
    val country: String
    val pinCode: Int

    init {
        if (line1.isNullOrBlank())
            throw IllegalArgumentException("Line1 must not be null or blank.")

        if (city.isNullOrBlank())
            throw IllegalArgumentException("City must not be null or blank.")
        if (state.isNullOrBlank())
            throw IllegalArgumentException("State must not be null or blank.")
        if (country.isNullOrBlank())
            throw IllegalArgumentException("Country must not be null or blank.")
        if (pinCode == null)
            throw IllegalArgumentException("Pin code must not be null.")

        this.line1 = line1
        this.line2 = line2
        this.city = city
        this.state = state
        this.country = country
        this.pinCode = pinCode
    }

    class Builder {
        private var line1: String? = null
        private var city: String? = null
        private var state: String? = null
        private var country: String? = null
        private var pinCode: Int? = null
        private var line2: String? = null

        fun setLine1(line1: String?) = apply {
            this.line1 = line1
        }

        fun setLine2(line2: String?) = apply {
            this.line2 = line2
        }

        fun setCity(city: String?) = apply {
            this.city = city
        }

        fun setState(state: String?) = apply {
            this.state = state
        }

        fun setCountry(country: String?) = apply {
            this.country = country
        }

        fun setPinCode(pinCode: Int) = apply {
            this.pinCode = pinCode
        }

        fun build(): Address {
            return Address(
                line1 = line1,
                line2 = line2,
                city = city,
                state = state,
                country = country,
                pinCode = pinCode
            )
        }
    }
}

Company的Builder

class Company(
    name: String?
) {

    val name: String

    init {
        if (name.isNullOrBlank())
            throw IllegalArgumentException("Name must not be null or blank.")

        this.name = name
    }

    class Builder {
        private var name: String? = null

        fun setName(name: String) = apply {
            this.name = name
        }

        fun build(): Company {
            return Company(name)
        }
    }
}

Contact的Builder

class Contact(
    twitterHandle: String,
    githubHandle: String,
    phoneNumber: String,
    email: String,
) {
    val twitterHandle: String
    val githubHandle: String
    val phoneNumber: String
    val email: String

    init {
        this.twitterHandle = twitterHandle.ifBlank {
            throw IllegalArgumentException("Twitter handle must not be blank.")
        }

        this.githubHandle = githubHandle.ifBlank {
            throw IllegalArgumentException("GitHub handle must not be blank.")
        }

        this.phoneNumber = phoneNumber.ifBlank {
            throw IllegalArgumentException("Phone number must not be blank.")
        }

        this.email = email.ifBlank {
            throw IllegalArgumentException("Email must not be blank.")
        }
    }

    class Builder {
        private var twitterHandle: String = ""
        private var githubHandle: String = ""
        private var phoneNumber: String = ""
        private var email: String = ""

        fun setTwitterHandle(twitterHandle: String) = apply {
            this.twitterHandle = twitterHandle
        }

        fun setGithubHandle(githubHandle: String) = apply {
            this.githubHandle = githubHandle
        }

        fun setPhoneNumber(phoneNumber: String) = apply {
            this.phoneNumber = phoneNumber
        }

        fun setEmail(email: String) = apply {
            this.email = email
        }

        fun build(): Contact {
            return Contact(
                twitterHandle = twitterHandle,
                githubHandle = githubHandle,
                phoneNumber = phoneNumber,
                email = email
            )
        }
    }
}

Education的Builder

这个特殊点,Builder写到类外边。

class Education(
    school: String,
    yearOfPassing: Int?,
    degree: String? // optional
) {
    val school: String
    val yearOfPassing: Int
    val degree: String? // optional

    init {

        if (school.isBlank())
            throw IllegalArgumentException("School must not be blank.")

        if (yearOfPassing == null) {
            throw IllegalArgumentException("School must not be blank.")
        }

        this.school = school
        this.yearOfPassing = yearOfPassing
        this.degree = degree
    }
}
class EducationBuilder {
    private var school: String = ""
    private var yearOfPassing: Int? = null
    private var degree: String? = null // optional

    fun setSchool(school: String): EducationBuilder = apply {
        this.school = school
    }

    fun setYearOfPassing(yearOfPassing: Int?): EducationBuilder = apply {
        this.yearOfPassing = yearOfPassing
    }

    fun setDegree(degree: String?): EducationBuilder = apply {
        this.degree = degree
    }

    fun build(): Education {
        return Education(school, yearOfPassing, degree)
    }
}

使用举例

fun main() {
    val address = getAddress()
    val company = getCompany()
    val contact = getContact()
    
    val schoolEducation = getSchoolEducation()
    val universityEducation = getUniversityEducation()
    
    val educations = listOf(schoolEducation, universityEducation)

    val user = User.Builder()
        .setFirstName("Abhishek")
        .setLastName("Saxena")
        .setAddress(address)
        .setCompany(company)
        .setContact(contact)
        .setEducations(educations) // <- a list of education is set
        .build() // <- user object is built here

    val user1 = User.Builder()
        .setFirstName("Abhishek")
        .setLastName("Saxena")
        .setAddress(address)
        .setCompany(company)
        .addEducation(educations) // <- a list of education is added
                .build() // <- user object is built here

    val user2 = User.Builder()
        .setFirstName("Abhishek")
        .setLastName("Saxena")
        .setAddress(address)
        .addEducation(schoolEducation)
        .addEducation(universityEducation) // <- Education is added one at a time
        .build() // <- user object is built here
}

private fun getAddress(): Address = Address.Builder()
    .setLine1("test")
    .setCity("Delhi")
    .setState("Delhi")
    .setCountry("India")
    .setPinCode(123456)
    .build()

private fun getCompany(): Company = Company.Builder()
    .setName("ABC")
    .build()

private fun getContact(): Contact = Contact.Builder()
    .setEmail("abc@def.com")
    .build()

private fun getSchoolEducation(): Education = EducationBuilder()
    .setSchool("ABC School")
    .setYearOfPassing(2014)
    .build()

private fun getUniversityEducation(): Education = EducationBuilder()
    .setSchool("ABC University")
    .setDegree("B.Tech")
    .setYearOfPassing(2020)
    .build()

好处

  • 数据类本身构造方法为 private 避免了外界直接创建,限制只能通过Builder模式创建
  • 数据类里的属性具有不可修改性,保障了数据的一致性
  • 通过set方法灵活组装属性
  • 数据类的 init 代码块里对数据做了校验,不合规的情况抛出异常,避免了不合规数据的存在
  • 外界可以链式调用,优雅的创建处对象

参考文档:https://proandroiddev.com/builder-design-pattern-in-kotlin-c52e41bd6020

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/946994.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

打造三甲医院人工智能矩阵新引擎(一):文本大模型篇--基于GPT-4o的探索

一、引言 当今时代&#xff0c;人工智能技术正以前所未有的速度蓬勃发展&#xff0c;深刻且广泛地渗透至各个领域&#xff0c;医疗行业更是这场变革的前沿阵地。在人口老龄化加剧、慢性疾病患病率上升以及人们对健康需求日益增长的大背景下&#xff0c;三甲医院作为医疗体系的核…

mysql连接时报错1130-Host ‘hostname‘ is not allowed to connect to this MySQL server

不在mysql服务器上通过ip连接服务提示1130错误怎么回事呢。这个错误是因为在数据库服务器中的mysql数据库中的user的表中没有权限。 解决方案 查询mysql库的user表指定账户的连接方式 SELECT user, host FROM mysql.user;修改指定账户的host连接方式 update mysql.user se…

linux下安装达梦数据库v8详解

目录 操作系统、数据库 1、下载达梦数据库 2、安装前准备 2.1、建立数据库用户和组 2.2、修改文件打开最大数 2.3、挂载镜像 2.4、新建安装目录 3、数据库安装 4、配置环境变量 5、初始化数据库实例 6、注册服务 7、使用数据库 8、卸载数据库 9、多实例管理 10、…

低代码引擎插件开发:开启开发的便捷与创新之路

OneCode授权演示 一、低代码引擎与插件开发的概述 在当今快节奏的软件开发领域&#xff0c;低代码引擎正逐渐崭露头角。低代码引擎旨在让开发人员能够以最少的代码量创建功能丰富的应用程序&#xff0c;而其中的关键组成部分便是插件开发。低代码引擎通过提供可视化的开发环境…

多光谱图像的处理和分析方法有哪些?

一、预处理方法 1、辐射校正&#xff1a; 目的&#xff1a;消除或减少传感器本身、大气条件以及太阳光照等因素对多光谱图像辐射亮度值的影响&#xff0c;使得图像的辐射值能够真实反映地物的反射或发射特性。 方法&#xff1a;包括传感器校正和大气校正。传感器校正主要是根…

贪心算法概述

贪心算法总是作出当前看来最好的选择&#xff0c;是局部最优 可以使用贪心算法的问题一般具有两个重要的性质 贪心选择性质最优子结构性质 贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择来达到 其与动态规划的问题区别在于&#xff0c;动态规划算法通…

Git 下载问题及解决方法

在某些网络环境下&#xff0c;可能会遇到 Git 无法下载的问题&#xff0c;通常是由于网络限制或需要通过代理访问导致的。以下是常见的解决方法&#xff0c;包括设置代理、取消代理以及其他诊断方法。 1. 设置 Git 代理 在一些网络环境下&#xff0c;可能会使用工具&#xff0…

【算法刷题】数组篇

文章目录 数组中两个数的最⼤异或值找出所有⼦集的异或总和再求和 数组中两个数的最⼤异或值 leet code&#xff1a;https://leetcode.cn/problems/maximum-xor-of-two-numbers-in-an-array/description/暴力解法&#xff1a;【部分样例超时&#xff0c;通过不了&#xff0c;不…

硬件设计-关于ADS54J60的校准问题

目录 简介: 校准模分析: 交错的优势 交错挑战 S/2 fIN处产生杂散。失调不匹配杂散很容易识别,因为只有它位于fS/2处,并可轻松地进行补偿。增益、时序和带宽不匹配都会在输出频谱的fS/2 fIN 处产生杂散;因此,随之而来的问题是:如何确定它们各自的影响。图8以简单的…

python小项目:给复制出来的段落前添加星号

给复制出来的段落前添加星号 最终效果二、实现步骤2.1 编写python脚本2.2 批处理脚本2.3 运行脚本 三、用到知识3.1 pyperclip 模块 最终效果 说明&#xff1a;复制四段内容&#xff08;段落实际不做限制&#xff09;&#xff0c;在windows终端输入 bulletPointAdder&#xff0…

超声波信号采集传感器模块测试分析总结

一 概述 数字化和小型化是目前医学超声的主要发展趋势之一。传统的推车式、大探头超声设备体积巨大且价格昂贵&#xff0c;而现在市场中的小型化超声设备经过更新发展&#xff0c;在保证图像清晰和高分辨率的同时&#xff0c;不仅功能更完善、探头也更多样化。这些新型的小型设…

ArcGIS计算矢量要素集中每一个面的遥感影像平均值、最大值等统计指标

本文介绍在ArcMap软件中&#xff0c;基于矢量面要素集&#xff0c;计算在其中每一个面区域内&#xff0c;遥感影像的像元个数、平均值、总和等统计值&#xff0c;并将统计信息附加到矢量图层的属性表中的方法。 首先&#xff0c;明确一下本文的需求。现在有一个矢量面要素集&am…

AI大模型系列之七:Transformer架构讲解

目录 Transformer网络是什么&#xff1f; 输入模块结构&#xff1a; 编码器模块结构&#xff1a; 解码器模块: 输出模块结构&#xff1a; Transformer 具体是如何工作的&#xff1f; Transformer核心思想是什么&#xff1f; Transformer的代码架构 自注意力机制是什么…

家政预约小程序05活动管理

目录 1 搭建活动管理页面2 搭建活动规则页面3 搭建规则新增页面3 配置规则跳转4 搭建活动参与记录总结 上一篇我们介绍了活动管理的表结构设计&#xff0c;本篇我们介绍一下后台功能。 1 搭建活动管理页面 我们一共搭建了三个表&#xff0c;先搭建主表的后台功能。打开我们的后…

SpringCloud(二)--SpringCloud服务注册与发现

一. 引言 ​ 前文简单介绍了SpringCloud的基本简介与特征&#xff0c;接下来介绍每个组成部分的功能以及经常使用的中间件。本文仅为学习所用&#xff0c;联系侵删。 二. SpringCloud概述 2.1 定义 ​ Spring Cloud是一系列框架的有序集合&#xff0c;它巧妙地利用了Spring…

当生成式AI遇见数字孪生

吴付标 总部位于美国宾夕法尼亚州的Bentley软件公司&#xff0c;于金秋十月在枫叶之国加拿大名城温哥华举办一年一度的2024纵览基础设施大会暨光辉大奖赛。此次盛会吸引了来自全球的数百位行业精英&#xff0c;旨在探讨基础设施数智化的最新趋势&#xff0c;分享生态圈的创新成…

散度与旋度的探讨

一、散度的定义与物理意义 1. 散度的定义 散度(Divergence)是向量分析中的一个核心概念,用于描述一个向量场在某一点的源或汇的强度。在数学上,散度通常使用符号“div”表示。对于一个三维向量场F(x, y, z) = (Fx, Fy, Fz),其散度可以定义为: div F = ∂Fx/∂x + ∂Fy/…

英文字体:创意前卫杀手级标题海报封面设计粗体字体 Morne Display

看啊&#xff0c;设计师们&#xff01;Morne 刚刚进入字体游戏&#xff0c;让我们告诉你&#xff0c;它不是来玩的——认识我们的字体&#xff0c;它就像你早上的咖啡一样大胆。无论您是在制作杀手级标题、偷偷摸摸的副标题还是大胆的海报&#xff0c;Morne 都能为您提供前后、…

LLM - 使用 LLaMA-Factory 部署大模型 HTTP 多模态服务 (4)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/144881432 大模型的 HTTP 服务&#xff0c;通过网络接口&#xff0c;提供 AI 模型功能的服务&#xff0c;允许通过发送 HTTP 请求&#xff0c;交互…

【大模型系列】Mobile-Agent(2024.04)

Paper: https://arxiv.org/pdf/2401.16158Github: https://github.com/X-PLUG/MobileAgentAuthor: Junyang Wang et al. 北交、阿里巴巴 Mobile-agent核心工作&#xff1a; 首先使用视觉感知工具(检测和OCR模型)识别前端界面中文本和图像元素的精确位置 检测图标&#xff1a;…