Kotlin中的by关键字

参考链接

《Kotlin - By 关键字介绍》
《Kotlin实战》
《Kotlin中文文档》
《java_my_life的博客》

装饰器模式

装饰器模式又名包装模式,来以对客户透明的方式(客户端并不觉得修饰前后的区别)扩展对象的功能,是继承关系的一种替代方案。

在装饰模式中的角色有:

  • 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
  • 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。
  • 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
interface CanBeWorn{
void worn();
}

class UnderWear implements CanBeWorn{

@Override
public void worn() {
System.out.print("穿内衣");
}
}

/**
* 装饰器模式的核心
* 它的子类都可以代理执行注入类的worn()方法
*/
class Mother implements CanBeWorn{

private CanBeWorn canBeWorn;

public Mother(CanBeWorn canBeWorn){
this.canBeWorn = canBeWorn;
}

@Override
public void worn() {
canBeWorn.worn();
}
}

class Coat extends Mother{

public Coat(CanBeWorn canBeWorn) {
super(canBeWorn);
}

@Override
public void worn() {
super.worn();
System.out.println("穿上衣");
}
}

class Pants extends Mother{

public Pants(CanBeWorn canBeWorn) {
super(canBeWorn);
}

@Override
public void worn() {
super.worn();
System.out.println("穿裤子");
}
}

这个例子举的有些不太符合,但是基本上能说明装饰模式的过程。

1
2
3
CanBeWorn canBeWorn = new UnderWear();
CanBeWorn coat = new Coat(canBeWorn);
CanBeWorn pants = new Pants(coat);

装饰模式的简化

大多数情况下,装饰模式的实现都要比上面给出的示意性例子要简单。

如果只有一个ConcreteComponent类,那么可以考虑去掉抽象的Component类(接口),把Decorator作为一个ConcreteComponent子类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class UnderWear{

public void worn() {
System.out.print("穿内衣");
}
}

class Mother extends UnderWear{

private UnderWear underWear;

public Mother(UnderWear underWear){
this.underWear = underWear;
}

@Override
public void worn() {
underWear.worn();
}
}

class Coat extends Mother{

public Coat(UnderWear underWear) {
super(underWear);
}

@Override
public void worn() {
super.worn();
System.out.println("穿上衣");
}
}

class Pants extends Mother{

public Pants(UnderWear underWear) {
super(underWear);
}

@Override
public void worn() {
super.worn();
System.out.println("穿裤子");
}
}

类的代理

上面的代码用Kotlin实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
interface CanBeWorn {
fun worn()
}

class UnderWear : CanBeWorn {

override fun worn() {
println("穿内衣")
}
}

abstract class Mother(val canBeWorn: CanBeWorn) : CanBeWorn {

override fun worn() {
canBeWorn.worn()
}
}

class Coat(canBeWorn: CanBeWorn) : Mother(canBeWorn) {

override fun worn() {
super.worn()
println("穿上衣")
}
}

class Pants(canBeWorn: CanBeWorn) : Mother(canBeWorn) {

override fun worn() {
super.worn()
println("穿裤子")
}
}

fun main(args: Array<String>){
Pants(Coat(UnderWear())).worn()
}

在Kotlin中可以使用by关键字将接口的实现委托到另一个对象。

所以上面的

1
2
3
4
5
6
abstract class Mother(val canBeWorn: CanBeWorn) : CanBeWorn {

override fun worn() {
canBeWorn.worn()
}
}

可以修改如下

1
abstract class Mother(val canBeWorn: CanBeWorn) : CanBeWorn by canBeWorn

覆盖代理成员

编译器会使用 override 覆盖的实现而不是委托对象中的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface Base {
fun printMessage()
fun printMessageLine()
}

class BaseImpl(val x: Int) : Base {
override fun printMessage() { print(x) }
override fun printMessageLine() { println(x) }
}

class Derived(b: Base) : Base by b {
override fun printMessage() { print("abc") }
}

fun main() {
val b = BaseImpl(10)
Derived(b).printMessage()
Derived(b).printMessageLine()
}

>>> abc10

注意,以这种方式重写的成员不会在委托对象的成员中调用 ,委托对象的成员只能访问其自身对接口成员实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface Base {
val message: String
fun print()
}

class BaseImpl(val x: Int) : Base {
override val message = "BaseImpl: x = $x"
override fun print() { println(message) }
}

class Derived(b: Base) : Base by b {
// 在 b 的 `print` 实现中不会访问到这个属性
override val message = "Message of Derived"
}

fun main() {
val b = BaseImpl(10)
val derived = Derived(b)
derived.print()
println(derived.message)
}

>>> BaseImpl: x = 10
>>> Message of Derived

属性委托

不仅可以类代理,还可以代理类属性,监听属性变化。

1
2
3
class Example {
var p: String by Delegate()
}

语法是: val/var <属性名>: <类型> by <表达式>。在 by 后面的表达式是该 委托, 因为属性对应的 get()(与 set())会被委托给它的 getValue() 与 setValue() 方法。 属性的委托不必实现任何的接口,但是需要提供一个 getValue() 函数(与 setValue()——对于 var 属性)。 例如:

1
2
3
4
5
6
7
8
9
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}

operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}

当我们从委托到一个 Delegate 实例的 p 读取时,将调用 Delegate 中的 getValue() 函数, 所以它第一个参数是读出 p 的对象、第二个参数保存了对 p 自身的描述 (例如你可以取它的名字)。 例如:

1
2
3
4
val e = Example()
println(e.p)

>>> Example@33a17727, thank you for delegating ‘p’ to me!

标准委托

延迟属性lazy

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

1
2
3
4
5
6
7
8
9
10
11
12
13
val lazyValue: String by lazy {
println("computed!")
"Hello"
}

fun main() {
println(lazyValue)
println(lazyValue)
}

>>> computed!
>>> Hello
>>> Hello

可观察属性 Observable

Delegates.observable() 接受两个参数:初始值与修改时处理程序(handler)。 每当我们给属性赋值时会调用该处理程序(在赋值后执行)。它有三个参数:被赋值的属性、旧值与新值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}

fun main() {
val user = User()
user.name = "first"
user.name = "second"
}

>>> <no name> -> first
>>> first -> second

评论

Ajax Android AndroidStudio Animation Anroid Studio AppBarLayout Babel Banner Buffer Bulma ByteBuffer C++ C11 C89 C99 CDN CMYK COM1 COM2 CSS Camera Raw, 直方图 Chrome Class ContentProvider CoordinatorLayout C语言 DML DOM Dagger Dagger2 Darktable Demo Document DownloadManage ES2015 ESLint Element Error Exception Extensions File FileProvider Flow Fresco GCC Git GitHub GitLab Gradle Groovy HTML5 Handler HandlerThread Hexo Hybrid I/O IDEA IO ImageMagick IntelliJ Intellij Interpolator JCenter JNI JS Java JavaScript JsBridge Kotlin Lab Lambda Lifecycle Lint Linux Looper MQTT MVC MVP Maven MessageQueue Modbus Momentum MySQL NDK NIO NexT Next Nodejs ObjectAnimator Oracle VM Permission PhotoShop Physics Python RGB RS-232 RTU Remote-SSH Retrofit Runnable RxAndroid RxJava SE0 SSH Spring SpringBoot Statubar Style Task Theme Thread Tkinter UI UIKit UML VM virtualBox VS Code VUE ValueAnimator ViewPropertyAnimator Vue Vue.js Web Web前端 Workbench api apk bookmark by关键字 cli compileOnly computed css c语言 databases demo hexo hotfix html iOS icarus implementation init jQuery javascript launchModel logo merge methods mvp offset photos pug query rxjava2 scss servlet shell svg tkinter tomcat transition unicode utf-8 vector virtual box vscode watch webpack 七牛 下载 中介者模式 串口 临潼石榴 主题 书签 事件 享元模式 仓库 代理模式 位运算 依赖注入 修改,tables 光和色 内存 内核 内部分享 函数 函数式编程 分支 分析 创建 删除 动画 单例模式 压缩图片 发布 可空性 合并 同向性 后期 启动模式 命令 命令模式 响应式 响应式编程 图层 图床 图片压缩 图片处理 图片轮播 地球 域名 基础 增加 备忘录模式 外观模式 多线程 大爆炸 天气APP 太白山 头文件 奇点 字符串 字符集 存储引擎 宇宙 宏定义 实践 属性 属性动画 岐山擀面皮 岐山肉臊子 岐山香醋 工具 工厂模式 年终总结 开发技巧 异常 弱引用 恒星 打包 技巧 指令 指针 插件 插值 摄影 操作系统 攻略 故事 数据库 数据类型 数组 文件 新功能 旅行 旋转木马 时序图 时空 时间简史 曲线 杂谈 权限 枚举 架构 查询 标准库 标签选择器 样式 核心 框架 案例 桥接模式 检测工具 模块化 模板 模板引擎 模板方法模式 油泼辣子 泛型 洛川苹果 浅色状态栏 渲染 源码 源码分析 瀑布流 热修复 版本 版本控制 状态栏 状态模式 生活 留言板 相册 相对论 眉县猕猴桃 知识点 码云 磁盘 科学 笔记 策略模式 类图 系统,发行版, GNU 索引 组件 组合模式 绑定 结构 结构体 编码 网易云信 网格布局 网站广播 网站通知 网络 美化 联合 脚手架 膨胀的宇宙 自定义 自定义View 自定义插件 蒙版 虚拟 虚拟机 补码 补齐 表单 表达式 装饰模式 西安 观察者模式 规范 视图 视频 解耦器模式 设计 设计原则 设计模式 访问者模式 语法 责任链模式 贪吃蛇 转换 软件工程 软引用 运算符 迭代子模式 适配器模式 选择器 通信 通道 配置 链表 锐化 错误 键盘 闭包 降噪 陕西地方特产 面向对象 项目优化 项目构建 黑洞
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×