Skip to content

Commit f03bf88

Browse files
chore(examples): add Delegation examples
1 parent a635cd4 commit f03bf88

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Delegation
2+
3+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Delegation Pattern
2+
3+
<div class="language-kotlin" theme="idea">
4+
5+
```kotlin
6+
interface SoundBehaviour { // 1
7+
fun makeSound()
8+
}
9+
10+
class ScreamBehavior(val n:String): SoundBehaviour { // 2
11+
override fun makeSound() = println("${n.toUpperCase()} !!!")
12+
}
13+
14+
class RockAndRollBehavior(val n:String): SoundBehaviour { // 2
15+
override fun makeSound() = println("I'm The King of Rock 'N' Roll: $n")
16+
}
17+
18+
// Tom Araya is the "singer" of Slayer
19+
class TomAraya(n:String): SoundBehaviour by ScreamBehavior(n) // 3
20+
21+
// You should know ;)
22+
class ElvisPresley(n:String): SoundBehaviour by RockAndRollBehavior(n) // 3
23+
24+
fun main() {
25+
val tomAraya = TomAraya("Trash Metal")
26+
tomAraya.makeSound() // 4
27+
val elvisPresley = ElvisPresley("Dancin' to the Jailhouse Rock.")
28+
elvisPresley.makeSound()
29+
}
30+
```
31+
32+
</div>
33+
34+
In Kotlin it's easy to delegate method calls without any boilerplate.
35+
36+
1. The interface SoundBehaviour is defined. Later there will be one class that implements the method and another will
37+
also have the interface, but just delegates the method call.
38+
2. The class ScreamBehavior and RockAndRollBehavior actually implement the method.
39+
3. The class TomAraya and ElvisPresley just delegate the methods defined by the interface SoundBehaviour to the
40+
responsible implementation. But does not need any boilerplate to delegate the method call at all.
41+
4. Call makeSound() on tomAraya of type TomAraya or elvisPresley of type ElvisPresley and it is delegated to the
42+
associated class
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Delegated Properties
2+
3+
There's some new syntax: you can say `val 'property name': 'Type' by 'expression'`.
4+
The expression after `by` is the delegate, because `get()` and `set()` methods
5+
corresponding to the property will be delegated to it.
6+
Property delegates don't have to implement any interface, but they have
7+
to provide methods named `getValue()` and `setValue()` to be called. The full documentation is [here](http://kotlinlang.org/docs/reference/delegated-properties.html).
8+
9+
Let's try some code.
10+
11+
<div class="language-kotlin" theme="idea">
12+
13+
```kotlin
14+
import kotlin.reflect.KProperty
15+
16+
class Example {
17+
var p: String by Delegate() // 1
18+
19+
override fun toString() = "Example Class"
20+
}
21+
22+
class Delegate() {
23+
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String { // 2
24+
return "$thisRef, thank you for delegating '${prop.name}' to me!"
25+
}
26+
27+
operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: String) { // 2
28+
println("$value has been assigned to ${prop.name} in $thisRef")
29+
}
30+
}
31+
32+
fun main() {
33+
val e = Example()
34+
println(e.p)
35+
e.p = "NEW"
36+
}
37+
```
38+
39+
</div>
40+
41+
1. Delegated property `p` of type `String`
42+
2. Delegation methods. For immutable property only `getValue` is required.
43+
44+
### Stanard delegates
45+
46+
Kotlin standard library contains bunch of useful delegates, like `lazy`, `observable`, etc.
47+
48+
For example `lazy` is used in case lazy initialization.
49+
50+
<div class="language-kotlin" theme="idea">
51+
52+
```kotlin
53+
class LazySample {
54+
init {
55+
println("created!"); // 1
56+
}
57+
58+
val lazy: String by lazy {
59+
println("computed!") // 2
60+
"my lazy"
61+
}
62+
}
63+
64+
fun main() {
65+
val sample = LazySample() // 1
66+
println("lazy = ${sample.lazy}") // 2
67+
println("lazy = ${sample.lazy}") // 3
68+
}
69+
```
70+
71+
</div>
72+
73+
1. Property `lazy` is not initialized on object creation.
74+
2. The first call to `get()` executes the lambda expression passed to lazy() as an argument and remembers the result
75+
3. Subsequent calls to `get()` simply return the remembered result.
76+
77+
If you want thread safety, use blockingLazy() instead: it guarantees that the values will be computed only in one thread, and that all threads will see the same value.
78+
79+
### Properties in map
80+
81+
Properties stored in a map. This comes up a lot in applications like parsing JSON
82+
or doing other "dynamic" stuff.
83+
84+
<div class="language-kotlin" theme="idea">
85+
86+
```kotlin
87+
class User(val map: Map<String, Any?>) {
88+
val name: String by map // 1
89+
val age: Int by map // 1
90+
}
91+
92+
fun main() {
93+
val user = User(mapOf(
94+
"name" to "John Doe",
95+
"age" to 25
96+
))
97+
98+
println("name = ${user.name}, age = ${user.age}")
99+
}
100+
```
101+
102+
</div>
103+
104+
1. Delegates take values from the `map` (by the string keys - names of properties).
105+
106+
Of course, you can have mutable property as well, that will modify the map upon assignment (note that you'd need `MutableMap` instead of read-only `Map`).

0 commit comments

Comments
 (0)