Kotlin快速入门系列10

Kotlin的委托

委托模式是常见的设计模式之一。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。与Java一样,Kotlin也支持委托模式,通过关键字by。

类委托

类的委托即一个类中定义的方法实际是调用另一个类的对象的方法来实现的。例如下面的Java实例:

class RealPrinter { // the "delegate"
    void print() {
        System.out.print("something");
    }
}

class Printer { // the "delegator"
    RealPrinter p = new RealPrinter(); // create the delegate 
    void print() {
        p.print(); // delegation
    }
}

public class Main {
    // to the outside world it looks like Printer actually prints.
    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

可以看到在Java代码中printer 最终其实调用了RealPrinter的方法。用kotlin表示则需要用到by关键字:

// 创建接口
interface Base {
    fun print()
}

// 实现此接口的被委托的类
class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

// 通过关键字 by 建立委托类
class Derived(b: Base) : Base by b

fun main(args: Array<String>) {
    val b = BaseImpl(10)
    Derived(b).print() // 输出 10
}

在 Derived 声明中,by 子句表示,将 b 保存在 Derived 的对象实例内部,而且编译器将会生成继承自 Base 接口的所有方法, 并将调用转发给 b。

属性委托

属性委托指的是一个类的某个属性值不是在类中直接进行定义,而是将其托付给一个代理类,从而实现对该类的属性统一管理。
属性委托的具体语法格式如下:

val/var <属性名>: <类型> by <表达式>

· var/val:属性类型(可变/只读)

· 属性名:属性名称

· 类型:属性的数据类型

· 表达式:委托代理类

by 关键字之后的表达式就是委托, 属性的 get()和set() 方法将被委托给这个对象的 getValue() 和 setValue() 方法。属性委托不必实现任何接口, 但必须提供 getValue() 函数(对于 var属性,还需要 setValue() 函数)。

定义被委托的类

该类需要包含 getValue() 方法和 setValue() 方法,且参数 thisRef 为进行委托的类的对象,prop 为进行委托的属性的对象。实例如下:

import kotlin.reflect.KProperty
// 定义包含属性委托的类,KProperty是个接口
class PropertyExample {
    var str: String by Delegate()
}

// 委托的类
class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, 这里委托了 ${property.name} 属性"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("--- $thisRef 的 ${property.name} 属性赋值为 $value ---")
    }
}
fun main(args: Array<String>) {
    val example = PropertyExample()
    println(example.str)     // 访问该属性,调用 Delegate.getValue()

    example.str = "Google"   // 调用 Delegate.setValue()
    println(example.str)
}

对应的控制台输出结果为:

这里做一个简单的说明:

· thisRef:属性的拥有者;

· property:对属性的描述,是 KProperty<*> 类型或是它的父类;

· value:属性的值。

标准委托

Kotlin的标准库提供很多工厂方法来实现属性的委托:

· 延迟属性Lazy

通过 lazy 我们可以定义一个懒加载的属性,该属性的初始化不会再类创建的时候发生,而是在第一次用到它的时候赋值。

lazy() 是一个函数, 是接受一个 Lambda 表达式作为参数, 返回一个 Lazy <T> 实例的函数。其返回的实例可以作为实现延迟属性的委托:第一次调用 get() 会执行已传递给 lazy() 的 lamda 表达式并记录结果,后续调用 get() 只是返回记录的结果。

下面是kotlin的经典示例:

val lazyValue: String by lazy {
    println(" lazyValue print ")     // 第一次调用输出,第二次调用不执行
    "lazyValue print again"
}

fun main(args: Array<String>) {
    println(lazyValue)   // 第一次执行,执行两次输出表达式
    println(lazyValue)   // 第二次执行,只输出返回值
}

对应的输出结果为: 

· 可观察属性Observable

observable,让属性在发生变动的时候可以被关注的地方观察到。可以用于实现观察者模式。

Delegates.observable() 函数接受两个参数: 第一个是初始化值, 第二个是属性值变化事件的响应器(handler)。

在属性赋值后会执行事件的响应器(handler),它有三个参数:被赋值的属性、旧值和新值:

import kotlin.properties.Delegates

class ObserveUser {
    var name: String by Delegates.observable("初始值") {
            prop, old, new ->
        println("旧值:$old -> 新值:$new")
    }
}

fun main(args: Array<String>) {
    val user = ObserveUser()
    user.name = "第一次赋值"
    user.name = "第二次赋值"
}

对应控制台输出为:

· 属性存储在映射中

常见的用法是在一个映射(map)里存储属性的值。这种情况经常出现在像解析 JSON 或者做其他"动态"事情的应用中。这种情况下,可以使用映射实例自身作为委托来实现委托属性。

class WebSite(val map: MutableMap<String, Any?>) {
    val company: String by map
    val url: String by map
}

fun main(args: Array<String>) {

    var map:MutableMap<String, Any?> = mutableMapOf(
        "company" to "谷歌大法好",
        "url" to "www.Google.com"
    )

    val site = WebSite(map)

    println(site.company)
    println(site.url)

    println("--------------")
    map.put("company", "白度全广告")
    map.put("url", "www.baiduu.com")

    println(site.company)
    println(site.url)

}

对应的输出结果为:

局部委托属性

局部变量可以声明为委托属性。比如使用lazy初始化一个局部变量:

fun example(computeFoo: () -> Foo) {
    val memoizedFoo by lazy(computeFoo)

    if (someCondition && memoizedFoo.isValid()) {
        memoizedFoo.doSomething()
    }
}

上述代码中,memoizedFoo 变量只会在第一次访问时计算。 如果 someCondition 失败,那么该变量根本不会计算。

属性委托的特点

对于只读属性(val属性), 它的委托必须提供一个getValue()函数。该函数接受以下参数:

· thisRef —— 必须与属性所有者类型(对于扩展属性——指被扩展的类型)相同或者是它的超类型;

· property —— 必须是类型 KProperty<*> 或其超类型。

这个函数必须返回与属性相同的类型(或其子类型)

对于一个值可变(mutable)属性(var属性),除getValue()函数之外,它的委托还必须再提供一个setValue()函数, 这个函数接受以下参数:

· property —— 必须是类型 KProperty<*> 或其超类型;

· new value —— 必须和属性同类型或者是它的超类型。

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

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

相关文章

东南亚独立站的黄金机会-东南亚服务器租用托管的选择

作为一个独立站的企业&#xff0c;选择将服务器托管或租用东南亚的服务器是一个明智的决策。东南亚市场是一个适合做独立站的国家。 1、东南亚的社交媒体用户非常活跃。东南亚地区的人口众多&#xff0c;其中很大一部分人使用社交媒体平台进行社交和购物。据统计&#xff0c;东…

喜报|博睿数据算力调度可观测平台荣获信通院“算力服务领航者计划”优秀案例

近日&#xff0c;中国通信标准化协会云计算标准和开源推进委员会2023年度工作总结会暨算力服务工作组成果发布会在京举行。会上&#xff0c;“2023年算力服务领航者计划优秀案例名单”正式公布&#xff0c;博睿数据的核心产品算力调度可观测平台 Bonree ONE成功入选&#xff0c…

WordPress主题YIA的文章页评论内容为什么没有显示出来?

有些WordPress站长使用YIA主题后&#xff0c;在YIA主题设置的“基本”中没有开启“一键关闭评论功能”&#xff0c;而且文章也是允许评论的&#xff0c;但是评论框却不显示&#xff0c;最关键的是文章原本就有的评论内容也不显示&#xff0c;这是为什么呢&#xff1f; 根据YIA主…

获取真实 IP 地址(一):判断是否使用 CDN(附链接)

一、介绍 CDN&#xff0c;全称为内容分发网络&#xff08;Content Delivery Network&#xff09;&#xff0c;是一种网络架构&#xff0c;旨在提高用户对于网络上内容的访问速度和性能。CDN通过在全球各地部署分布式服务器节点来存储和分发静态和动态内容&#xff0c;从而减少…

2024牛客寒假训练营1总结

G题不开long long的后果&#xff0c;即使有思路也没用。(给我气的) E题&#xff0c;不看数据范围的后果&#xff0c;不能一题名取题啊。 using ll long long; void solve() {int n, m;std::cin >> n >> m;std::vector<int>a(n);for (int i 0; i < n; i)…

【python】英语单词文本处理

文章目录 前言一、环境实验所需的库终端指令 二、实现过程Version 1 起源Version 2 listVersion 3 arrayVersion 4 结构化数组Version 5 区分单元且打乱顺序Version 6 可视化 三、txt文件 前言 缘起自懒得考小孩儿单词&#xff0c;最终效果如图&#xff1a; 本文记录了英语单词…

2024美赛数学建模B题思路分析 - 搜索潜水器

1 赛题 问题B&#xff1a;搜索潜水器 总部位于希腊的小型海上巡航潜艇&#xff08;MCMS&#xff09;公司&#xff0c;制造能够将人类运送到海洋最深处的潜水器。潜水器被移动到该位置&#xff0c;并不受主船的束缚。MCMS现在希望用他们的潜水器带游客在爱奥尼亚海底探险&…

react 之 useCallback

简单讲述下useCallback的使用方法&#xff0c;useCallback也是用来缓存的&#xff0c;只不过是用于做函数缓存 // useCallbackimport { memo, useCallback, useState } from "react"const Input memo(function Input ({ onChange }) {console.log(子组件重新渲染了…

物流自动化移动机器人|HEGERLS三维智能四向穿梭车助力优化企业供应链

智能化仓库/仓储贯穿于物流的各个环节&#xff0c;不局限于存储、输送、分拣、搬运等单一作业环节的自动化&#xff0c;更多的是利用科技手段实现整个物流供应链流程的自动化与智能化&#xff0c;将传统自动化仓储物流各环节进行多维度的有效融合。 例如在数智化物流仓储的建设…

OpenHarmony—Hap包签名工具

概述 为了保证OpenHarmony应用的完整性和来源可靠&#xff0c;在应用构建时需要对应用进行签名。经过签名的应用才能在真机设备上安装、运行、和调试。developtools_hapsigner仓 提供了签名工具的源码&#xff0c;包含密钥对生成、CSR文件生成、证书生成、Profile文件签名、Ha…

华为数通方向HCIP-DataCom H12-821题库(单选题:401-420)

第401题 R1的配置如图所示,此时在R1查看FIB表时,关于目的网段192.168.1.0/24的下跳是以下哪一项? A、10.0.23.3 B、10.0.12.2 C、10.0.23.2 D、10.0.12.1 【答案】A 【答案解析】 该题目考查的是路由的递归查询和 RIB 以及 FIB 的关系。在 RIB 中,静态路由写的是什么,下…

Node.js之内存限制理解_对处理前端打包内存溢出有所帮助

Node.js内存限制理解_对处理前端打包内存溢出有所帮助 文章目录 Node.js内存限制理解_对处理前端打包内存溢出有所帮助Node.js内存限制1. 查看Node.js默认内存限制1. Ndos.js_V20.10.02. Node.js_V18.16.0 2. V8引擎垃圾回收相关Heap organization堆组织 Node.js内存限制 默认情…

(十二)springboot实战——SSE服务推送事件案例实现

前言 SSE&#xff08;Server-Sent Events&#xff0c;服务器推送事件&#xff09;是一种基于HTTP协议的服务器推送技术。它允许服务器向客户端发送异步的、无限长的数据流&#xff0c;而无需客户端不断地轮询或发起请求。这种技术可以用来实现实时通信、在线聊天、即时更新等功…

Entity实体设计

Entity实体设计 &#x1f4a1;用来和数据库中的表对应&#xff0c;解决的是数据格式在Java和数据库间的转换。 &#xff08;一&#xff09;设计思想 数据库Java表类行对象字段&#xff08;列&#xff09;属性 &#xff08;二&#xff09;实体Entity编程 编码规范 &#x1f4a…

文本检测学习笔记_CTPN

论文地址&#xff1a;https://arxiv.org/pdf/1609.03605.pdf 开源代码&#xff1a;https://github.com/lvliguoren/pytorch_ctpn?tabreadme-ov-file 本文主要的的内容 提出了一种将文本视为由密集排列的具有固定宽度的文本候选区域组成的序列的方法。这些文本候选区域可以通…

三.Linux权限管控 1-5.Linux的root用户用户和用户组查看权限控制信息chmod命令chown命令

目录 三.Linux权限管控 1.Linux的root用户 root用户&#xff08;超级管理员&#xff09; su和exit命令 sudo命令 为普通用户配置sudo认证 三.Linux权限管控 2.用户和用户组 用户&#xff0c;用户组 用户组管理 用户管理 getent---查看系统中的用户 三.Linux权限管控…

[每周一更]-(第86期):NLP-实战操作-文本分类

NLP文本分类的应用场景 医疗领域 - 病历自动摘要&#xff1a; 应用&#xff1a; 利用NLP技术从医疗文档中自动生成病历摘要&#xff0c;以帮助医生更快速地了解患者的状况。 法律领域 - 法律文件分类&#xff1a; 应用&#xff1a; 使用文本分类技术自动分类法律文件&#xf…

【网络安全实验】snort实现高级IDS

注&#xff1a;本实验分别使用kali和CentOS6.8进行测试&#xff0c;可惜的是使用kali进行实验过程中遇到了困难&#xff0c;未能完成完整实验&#xff0c;而使用CentOS6.8成功完成了完整实验。 实验中用到的软件&#xff1a; https://download.csdn.net/download/weixin_5255…

Spring-集成Web

一、引子 前面我们在Spring集成Junit中为读者引出了Spring善于集成其它框架的优势&#xff0c;而Spring项目不可能仅限于小范围的某个方法的测试&#xff0c;终究会落脚于Web项目上。于是&#xff0c;我们就从这里正式进入Spring集成Web的话题。由于笔者会从原生的Java Web开发…

【Spark实践6】特征转换FeatureTransformers实践Scala版--补充算子

本节介绍了用于处理特征的算法&#xff0c;大致可以分为以下几组&#xff1a; 提取&#xff08;Extraction&#xff09;&#xff1a;从“原始”数据中提取特征。转换&#xff08;Transformation&#xff09;&#xff1a;缩放、转换或修改特征。选择&#xff08;Selection&…