当前位置: 首页 > news >正文

Kotlin 中的 设计模式

单例模式

饿汉模式

饿汉模式在类初始化的时候就创建了对象,所以不存在线程安全问题。

局限性:

1、如果构造方法中有耗时操作的话,会导致这个类的加载比较慢;

2、饿汉模式一开始就创建实例,但是并没有调用,会造成资源浪费;

java模式下

public class ModelJavaTest {private static ModelJavaTest mInstance = new ModelJavaTest();public static ModelJavaTest getInstance(){return mInstance;}}

Kotlin 

class ModelKotlinTest {object ModelKotlinTest{}
}

双重检查锁单例(DCL)

java

class SingleJavaClass {private volatile static SingleJavaClass instance;public static SingleJavaClass getInstance() {if (instance == null) {synchronized (SingleJavaClass.class) {if (instance == null) {instance = new SingleJavaClass();}}}return instance;}
}

kotlin

class SingKotlinClass {companion object {val instance: SingKotlinClass by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { SingKotlinClass() }}
}

工厂模式

java

//水果抽象类
interface Fruit {void showPrice();//水果价格
}abstract class AbsFruit implements Fruit {public float mPrice;
}class Apple extends AbsFruit {public Apple(float price) {mPrice = price;}@Overridepublic void showPrice() {System.out.println("apple price is " + mPrice);}
}class Banana extends AbsFruit {public Banana(float price) {mPrice = price;}@Overridepublic void showPrice() {System.out.println("Banana price is " + mPrice);}
}class FruitFactory {public static Fruit getApple() {return new Apple(5.0f);}public static Fruit getBanana() {return new Banana(8.0f);}public static void main(String[] args) {Fruit apple = FruitFactory.getApple();apple.showPrice();}
}

kotlin

interface FruitKotlin {val price: Floatfun showPrice()
}class FruitFactoryKotlin {companion object {fun getApple() = AppleKotlin(5.0f)fun getBanana() = BananaKotlin(8f)}
}class AppleKotlin(override val price: Float) : FruitKotlin {override fun showPrice() {println("apple price is $price")}
}class BananaKotlin(override val price: Float) : FruitKotlin {override fun showPrice() {println("banana price is $price")}
}

builder模式

builder模式也是一种常用的设计模式,常用于复杂对象的构建,例如 Android 中的 AlertDialog.

可变参数

class Car(val color: String = "black", val factory: String = "Audi")fun main() {val redCar = Car(color = "red")//只关心颜色val bmwCar = Car(factory = "BMW")//只关心品牌
}

apply方法

apply函数时 kotlin 标准库的函数。我们先看看使用 apply 是如何构建对象

class Car2 {var color = "black"var factory = "Audi"
}fun t() {val newCar = Car2().apply {factory = "BMW"color = "red"}
}

看一下 apply 函数 的实现

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE)}block()return this
}

从源码中可以看出,apply 函数其实是类型 T 的扩展函数。参数是一个带接受者的 lambda 表达式,执行我传入的 block 后,会把当前实例返回。 kotlin 中,可以在任何对象上使用 apply 函数,不需要额外的支持。 apply 函数的一种使用方式就是创建一个对象实例并且按照正确的方式初始化他的一些属性。和 java 当中的 builder 模式死异曲同工的效果,但是使用起来要简洁很多。

原型模式 

扩展函数

interface Shape {fun draw()
}class Circle : Shape {override fun draw() {println("draw Circle")}
}fun Circle.redColor(decorator: Shape.() -> Unit) {println("with red color extend")decorator()
}fun Shape.boldLine(decorator: Shape.() -> Unit) {println("with bold line extend")decorator()
}fun t2() {Circle().run {boldLine {redColor {draw()}}}
}

采用扩展函数的方式实现装饰者模式,没有中间的装饰类,代码简洁。但是只能装饰一个方法,对于多个方法都需要装饰的情况下,可能使用委托更为适合。

类委托使用 by 关键字

使用 by 关键字可以将一个接口的实现委托到实现了同样接口的另外一个对象,没有任何样板代码的产生,下面是用委托的方式实现装饰者模式。

interface Shape {fun draw()fun prepare()fun release()
}class Circle : Shape {override fun draw() {println("draw Circle")}override fun prepare() {println("prepare Circle")}override fun release() {println("release Circle")}
}class RedShapeKotlin(val shape: Shape) : Shape by shape {override fun draw() {println("with red color by")shape.draw()}
}class BoldShapeKotlin(val shape: Shape) : Shape by shape {override fun draw() {println("with bold line by")shape.draw()}
}fun test() {val circle = Circle()val decoratorShape = BoldShapeKotlin(RedShapeKotlin(shape = circle))decoratorShape.draw()
}

输出: 

with bold line by
with red color by
draw Circle 

小结:

Kotlin 将委托做为了语言级别的功能做了头等支持,委托是替代继承的一个很好的方法,如果多个地方需要用到相同的代码,这个是就可以考虑使用委托。

策略模式 

策略模式通常是把一系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。简单理解,策略模式就是对一个算法的不同实现。kotlin 中可以使用高阶函数替代不同算法。我么看下代码实现。

fun fullDisCount(money: Int): Int {return if (money > 200)money - 100elsemoney
}fun newDisCount(money: Int): Int {return money / 2
}class Customer(val discount: ((Int) -> Int)) {fun caculate(money: Int): Int {return discount(money)}
}fun test2() {val newCustomer = Customer(::newDisCount)val value = newCustomer.caculate(1000)val fullDiscountCustomer = Customer(::fullDisCount)val value2 = fullDiscountCustomer.caculate(300)println("value : $value value2: $value2")
}

输出:

value : 500 value2: 200

 模版方法

模板方法知道思想,定义一个算法中的操作框架,而将一些步骤延迟到子类中,使得子类在不改变算法框架结构即可重新定义该算法的某些特定步骤。这个模式与上面的策略模式有类似的效果。都是把不同算法实现延迟到子类中实现。与策略模式不同的是,模板行为算法有更清晰的大纲结构。完全相同的步骤会在抽象类中实现。个性化实现会在子类中实现。下面的例子展示了在线购物通过模板方法的模式支持不同的支付方式。这里和上面的策略模式类似,减少了子类的创建。

class OnLineShopping {fun submitOrder(pay: () -> Unit) {accumulatePrice()pay()sendHome()}private fun sendHome() {println("send home!")}private fun accumulatePrice() {println("accumulate price!")}fun weChatPay() {println("pay by weChat")}fun aliPay() {println("pay by aliPay")}}fun test3() {var shopping = OnLineShopping()shopping.submitOrder { shopping.weChatPay() }shopping.submitOrder { shopping.aliPay() }
}

输出:

accumulate price!
pay by weChat
send home!


accumulate price!
pay by aliPay
send home!

小结:

策略模式和模版方法模式都是通过高阶函数的替代继承的方式,减少了子类的创建。极大的精简了我们的代码结构。这也是我们在学习 kotlin 的时候,需要注意的地方。函数是 kotlin 中的一等公民,函数本身也具有自己的类型。函数类型和数据类型一样,即可用于定义变量,也可用作函数的形参类型,还可作为函数的返回值类型。

观察者模式 

观察者模式是应用较多的一种设计模式,尤其在响应式编程中。

一些知名框架 EventBus,RxJava等,都是基于观察者模式。 Android jetpack 中的LiveData 也是采用的观察者模式,可见这种模式应用的很广泛,看一下这个例子,用户订阅了某些视频号后,这个视频号一旦有更新,需要通知所有的订阅者用户。

interface VideoUpdateListener {fun update(message: String)
}class VideoObservableInKotlin {var observers: MutableList<UserInKotlin> = ArrayList()var vid: Int by Delegates.observable(0) { _, old, new ->observers.forEach {//it.update("${it.name}_$vid")if (old == new) it.update("no new value")else it.update("${it.name}_$vid")}}
}class UserInKotlin(val name: String) : VideoUpdateListener {override fun update(message: String) {println(message)}
}fun test4() {val videoUpdates = VideoObservableInKotlin()videoUpdates.observers.add(UserInKotlin("Allen"))videoUpdates.observers.add(UserInKotlin("Bob"))videoUpdates.vid = 101videoUpdates.vid = 102
}

输出:

Allen_101
Bob_101
Allen_102
Bob_102

分析上面的代码,主要也是通过委托属性的方式实现了对属性值改变的监听。这里用到了一个 kotlin 标准函数 Delegates.observable 该函数有两个参数,接受一个初始值,和一个属性改变后的回调函数,回调函数有三个参数,第一个是被赋值的属性,第二个是旧值,第三个是 新值开发者可以根据自己的需求,实现属性改变后的逻辑。

相关文章:

Kotlin 中的 设计模式

单例模式 饿汉模式 饿汉模式在类初始化的时候就创建了对象&#xff0c;所以不存在线程安全问题。 局限性&#xff1a; 1、如果构造方法中有耗时操作的话&#xff0c;会导致这个类的加载比较慢&#xff1b; 2、饿汉模式一开始就创建实例&#xff0c;但是并没有调用&#xf…...

Vulnhub: ICMP: 1靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.208 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.208 80端口的cms为Monitorr 1.7.6m 搜索发现该版本的cms存在远程代码执行 searchsploit monitorr 漏洞利用 nc本地监听&…...

我的创作纪念日(C++修仙练气期总结)

分享自己最喜欢的一首歌&#xff1a;空想フォレスト—伊東歌詞太郎 机缘 现在想想自己在CSDN创作的原因&#xff0c;一开始其实就是想着拿着博客当做自己的学习笔记&#xff0c;笔记嘛&#xff0c;随便写写&#xff0c;自己看得懂就ok了的态度凸(艹皿艹 )。也是用来作为自己学习…...

css的常见伪元素使用

1.first-line 元素首行设置特殊样式。 效果演示&#xff1a; <div class"top"><p>可以使用 "first-line" 伪元素向文本的首行设置特殊样式。<br> 换行内容 </p></div> .top p::first-line {color: red;} 2.first-lette…...

91. 解码方法

递归法&#xff1a;超时了 从字符串的后面向前计算&#xff0c;每一次递归都缩小子集 public class Solution {public int NumDecodings(string s) {return RecursiveAdd(s, s.Length - 1);}public int RecursiveAdd(string s, int index) {// 已经到最后一个元素if(index <…...

docker搭建opengrok环境2

引言&#xff1a; 虚拟机关闭后重新开启&#xff0c;理论上是需要重新启动一下docker的&#xff0c;以重新启动其中的服务。 命令基础&#xff1a; docker images&#xff1a;查看docker中现有的镜像 docker container ls -all&#xff1a;查看docker中目前在运行的containe…...

【校招VIP】java语言考点之ConcurrentHashMap1.7和1.8

考点介绍&#xff1a; ConcurrentHashMap是JAVA校招面试的热门考点&#xff0c;主要集中在1.7和1.8的底层结构和相关的性能提高。 理解这个考点要从map本身的并发问题出发&#xff0c;再到hashTable的低性能并发安全&#xff0c;引申到ConcurrentHashMap的分块处理。同时要理解…...

php如何实现5x+2x+1x=100

要实现5x 2x 1x 100的计算&#xff0c;可以使用PHP来解方程。以下是一个简单的PHP代码示例&#xff1a; php <?php $x 1; // 初始化x的值while (5*$x 2*$x 1*$x ! 100) { // 循环直到方程成立$x; // 每次循环增加x的值 }echo "x " . $x; // 输出x的值 ?…...

机器人项目:从 ROS2 切换到 ROS1 的原因

一、说明 机器人操作系统ROS是使用最广泛的机器人中间件平台。它在机器人社区中使用了10多年&#xff0c;无论是在业余爱好者领域还是在工业领域。ROS可用于各种微控制器和计算机&#xff0c;从Arduino到Raspberry Pi再到Linux工作站&#xff0c;它为电机控制器&#xff0c;视觉…...

Vault主题 - UiCore多用途Elementor WordPress主题

你可以使用Vault主题 – UiCore多用途Elementor WordPress主题构建什么&#xff1f; Vault主题拥有专业、像素级完美且干净的现代布局&#xff0c;几乎适合您需要的任何网站&#xff1a; 小型企业网站企业网站着陆页面权威博客销售和营销页面网上商店 自由职业者的最佳选择 …...

G0第26章:微服务概述与gRPCprotocol buffers

Go微服务与云原生 1、微服务架构介绍 单体架构&#xff08;电商&#xff09; SOA架构&#xff08;电商&#xff09; 微服务架构&#xff08;电商&#xff09; 优势 挑战 拆分 发展史 第一代:基于RPC的传统服务架构 第二代:Service Mesh(istio) 微服务架构分层 核心组件 Summar…...

三款远程控制软件对比,5大挑选指标:安全、稳定、易用、兼容、功能

陈老老老板&#x1f934; &#x1f9d9;‍♂️本文专栏&#xff1a;生活&#xff08;主要讲一下自己生活相关的内容&#xff09;生活就像海洋,只有意志坚强的人,才能到达彼岸。 &#x1f9d9;‍♂️本文简述&#xff1a;三款远程控制软件对比&#xff0c;5大挑选指标&#xff1…...

Java中static的应用之单例模式

单例模式是一种创建对象的设计模式&#xff0c;它保证一个类只有一个实例&#xff0c;并提供一个全局访问点。由于单例模式只允许存在一个实例&#xff0c;因此它可以节省系统资源并提高程序的性能。在许多情况下&#xff0c;单例模式在应用程序中都是非常有用的&#xff0c;例…...

TypeError: Cannot read properties of undefined (reading ‘container‘)

问题环境&#xff1a; element项目 el-table的错误 项目是由 webpack项目迁移为 vite项目 问题描述&#xff1a; errorLog.js?t1692581753160:17 TypeError: Cannot read properties of undefined (reading container) at unbind (infinite-scroll.js:259:31) …...

Vue--BM记事本

效果如下&#xff1a; 用到了如下的技术&#xff1a; 1.列表渲染&#xff1a;v-for key的设置 2.删除功能&#xff1a;v-on调用参数 fliter过滤 覆盖修改原数组 3.添加功能&#xff1a;v-model绑定&#xff0c;unshift修改原数组添加 html文件如下&#xff1a; <!DOCTYPE …...

openpnp - 板子上最小物料封装尺寸的选择

文章目录 openpnp - 板子上最小物料封装尺寸的选择概述END openpnp - 板子上最小物料封装尺寸的选择 概述 现在设备调试完了, 用散料飞达载入物料试了一下. 0402以上贴的贴别准, 贴片流程也稳, 基本不需要手工干预. 0201可以贴, 但是由于底部相机元件视觉识别成功率不是很高…...

什么是非功能性需求,它们如何影响产品开发?

我们在选购新车时&#xff0c;会预设一些选购的标准&#xff0c;比如GPS导航必须能够保存目的地&#xff0c;或者必须要买黑色的车。我们可能下意识以为这些是功能性需求&#xff0c;但实际上这些特性都是与用户体验相关的非功能性需求。 一、什么是非功能性需求(NFR)? 非功…...

Oracle jdk8 exe->zip

一、背景 目前Oracle网站对应jdk8安装windows仅存在exe安装包&#xff0c;对于某些用户一台机器上对应jdk版本需动态切换&#xff0c;故需使用zip版本jdk&#xff0c;更加方便&#xff0c;本文介绍如何从jdk对应exe提取zip。 二、步骤 下载jdk8对应exe安装包&#xff1b;使用…...

Android 命令行如何运行 JAR 文件

​ 最近有位老哥问了一个问题&#xff0c;说如果将java的jar文件在Android中执行&#xff1f;这个其实很简单的一个问题&#xff0c;直接写个App放里面不就可以了么&#xff1f;但是人家说没有App&#xff0c;直接使用命令行去运行。说明这个需求的时候&#xff0c;把我给整懵了…...

5.4 webrtc的线程

那今天呢&#xff1f;我们来了解一下webrtc中的threed&#xff0c;首先我们看一下threed的类&#xff0c;它里边儿都含了哪些内容&#xff1f;由于threed的类非常大啊&#xff0c;我们将它分成两部分。 那第一部分呢&#xff0c;是我们看threed的类中都包含了哪些数据之后呢&a…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...