@@ -155,7 +155,7 @@ only support single inheritance. If you need to inherit from multiple sources, c
155
155
Interfaces are similar to classes, but they have some differences:
156
156
157
157
* You can't create an instance of an interface. They don't have a constructor or header.
158
- * Their functions and properties are implicitly inheritable by default. In Kotlin, we say that they are "open".
158
+ * Their functions and properties are implicitly inheritable by default. In Kotlin, we say that they are "open."
159
159
* You don't need to mark their functions as ` abstract ` if you don't give them an implementation.
160
160
161
161
Similar to abstract classes, you use interfaces to define a set of functions and properties that classes can inherit and
@@ -269,87 +269,184 @@ For more information about interfaces and interface inheritance, see [Interfaces
269
269
270
270
## Delegation
271
271
272
- Interfaces are useful, but if your interface contains many functions, child classes may end up with a lot of
273
- boilerplate code. When you only want to override a small part of your parent 's behavior, you need to repeat yourself a lot.
272
+ Interfaces are useful, but if your interface contains many functions, its child classes can end up with a lot of
273
+ boilerplate code. If you only want to override a small part of a class 's behavior, you need to repeat yourself a lot.
274
274
275
275
> Boilerplate code is a chunk of code that is reused with little or no alteration in multiple parts of a software project.
276
276
>
277
277
{style="tip"}
278
278
279
- For example, let's say that you have an interface called ` Drawable ` that contains a number of functions and one property
279
+ For example, let's say that you have an interface called ` DrawingTool ` that contains a number of functions and one property
280
280
called ` color ` :
281
281
282
282
``` kotlin
283
- interface Drawable {
284
- fun draw ()
285
- fun resize ()
286
- val color: String?
283
+ interface DrawingTool {
284
+ val color: String
285
+ fun draw (shape : String )
286
+ fun erase (area : String )
287
+ fun getToolInfo (): String
287
288
}
288
289
```
289
290
290
- You create a class called ` Circle ` which implements the ` Drawable ` interface and provides implementations for all of
291
+ You create a class called ` PenTool ` which implements the ` DrawingTool ` interface and provides implementations for all of
291
292
its members:
292
293
293
294
``` kotlin
294
- class Circle : Drawable {
295
- override fun draw () {
296
- TODO (" An example implementation" )
295
+ class PenTool : DrawingTool {
296
+ override val color: String = " black"
297
+
298
+ override fun draw (shape : String ) {
299
+ println (" Drawing $shape using a pen in $color " )
297
300
}
298
-
299
- override fun resize () {
300
- TODO (" An example implementation" )
301
+
302
+ override fun erase (area : String ) {
303
+ println (" Erasing $area with pen tool" )
304
+ }
305
+
306
+ override fun getToolInfo (): String {
307
+ return " PenTool(color=$color )"
301
308
}
302
- override val color = null
303
309
}
304
310
```
305
311
306
- If you wanted to create a child class of the ` Circle ` class which had the same behavior ** except** for the value of the
307
- ` color ` property, you still need to add implementations for each member function of the ` Circle ` class:
312
+ You want to create a class like ` PenTool ` with the same behavior but a different ` color ` value.
313
+ One approach is to create a new class that expects an object implementing the ` DrawingTool ` interface as a parameter,
314
+ like a ` PenTool ` class instance. Then, inside the class, you can override the ` color ` property.
315
+
316
+ But in this scenario, you need to add implementations for each member of the ` DrawingTool ` interface:
308
317
309
318
``` kotlin
310
- class RedCircle (val circle : Circle ) : Circle {
319
+ interface DrawingTool {
320
+ val color: String
321
+ fun draw (shape : String )
322
+ fun erase (area : String )
323
+ fun getToolInfo (): String
324
+ }
325
+
326
+ class PenTool : DrawingTool {
327
+ override val color: String = " black"
328
+
329
+ override fun draw (shape : String ) {
330
+ println (" Drawing $shape using a pen in $color " )
331
+ }
332
+
333
+ override fun erase (area : String ) {
334
+ println (" Erasing $area with pen tool" )
335
+ }
336
+
337
+ override fun getToolInfo (): String {
338
+ return " PenTool(color=$color )"
339
+ }
340
+ }
341
+ // sampleStart
342
+ class CanvasSession (val tool : DrawingTool ) : DrawingTool {
343
+ override val color: String = " blue"
311
344
312
- // Start of boilerplate code
313
- override fun draw () {
314
- circle.draw()
345
+ override fun draw (shape : String ) {
346
+ tool.draw(shape)
315
347
}
316
348
317
- override fun resize ( ) {
318
- circle.resize( )
349
+ override fun erase ( area : String ) {
350
+ tool.erase(area )
319
351
}
320
352
321
- // End of boilerplate code
322
- override val color = " red"
353
+ override fun getToolInfo (): String {
354
+ return tool.getToolInfo()
355
+ }
356
+ }
357
+ // sampleEnd
358
+ fun main () {
359
+ val pen = PenTool ()
360
+ val session = CanvasSession (pen)
361
+
362
+ println (" Pen color: ${pen.color} " )
363
+ // Pen color: black
364
+
365
+ println (" Session color: ${session.color} " )
366
+ // Session color: blue
367
+
368
+ session.draw(" circle" )
369
+ // Drawing circle with pen in black
370
+
371
+ session.erase(" top-left corner" )
372
+ // Erasing top-left corner with pen tool
373
+
374
+ println (session.getToolInfo())
375
+ // PenTool(color=black)
323
376
}
324
377
```
378
+ {kotlin-runnable="true" id="kotlin-tour-interface-non-delegation"}
325
379
326
- You can see that if you have a large number of member functions in the ` Drawable ` interface, the amount of boilerplate
327
- code in the ` RedCircle ` class can be very large. However, there is an alternative.
380
+ You can see that if you have a large number of member functions in the ` DrawingTool ` interface, the amount of boilerplate
381
+ code in the ` CanvasSession ` class can be large. However, there is an alternative.
328
382
329
- In Kotlin, you can use delegation to delegate the interface implementation to an instance of a class. For example,
330
- you can create an instance of the ` Circle ` class and delegate the implementations of the member functions of the ` Circle `
331
- class to this instance. To do this, use the ` by ` keyword. For example:
383
+ In Kotlin, you can delegate the interface implementation to a class instance using the ` by ` keyword. For example:
332
384
333
385
``` kotlin
334
- class RedCircle ( param : Circle ) : Drawable by param
386
+ class CanvasSession ( val tool : DrawingTool ) : DrawingTool by tool
335
387
```
336
388
337
- Here, ` param ` is the name of the instance of the ` Circle ` class that the implementations of member functions are delegated to.
389
+ Here, ` tool ` is the name of the ` PenTool ` class instance where the implementations of member functions are delegated to.
338
390
339
- Now you don't have to add implementations for the member functions in the ` RedCircle ` class. The compiler does
340
- this for you automatically from the ` Circle ` class. This saves you from having to write a lot of boilerplate code. Instead,
391
+ Now you don't have to add implementations for the member functions in the ` CanvasSession ` class. The compiler does
392
+ this for you automatically from the ` PenTool ` class. This saves you from having to write a lot of boilerplate code. Instead,
341
393
you add code only for the behavior you want to change for your child class.
342
394
343
395
For example, if you want to change the value of the ` color ` property:
344
396
345
397
``` kotlin
346
- class RedCircle (param : Circle ) : Drawable by param {
398
+ interface DrawingTool {
399
+ val color: String
400
+ fun draw (shape : String )
401
+ fun erase (area : String )
402
+ fun getToolInfo (): String
403
+ }
404
+
405
+ class PenTool : DrawingTool {
406
+ override val color: String = " black"
407
+
408
+ override fun draw (shape : String ) {
409
+ println (" Drawing $shape using a pen in $color " )
410
+ }
411
+
412
+ override fun erase (area : String ) {
413
+ println (" Erasing $area with pen tool" )
414
+ }
415
+
416
+ override fun getToolInfo (): String {
417
+ return " PenTool(color=$color )"
418
+ }
419
+ }
420
+
421
+ // sampleStart
422
+ class CanvasSession (val tool : DrawingTool ) : DrawingTool by tool {
347
423
// No boilerplate code!
348
- override val color = " red"
424
+ override val color: String = " blue"
425
+ }
426
+ // sampleEnd
427
+ fun main () {
428
+ val pen = PenTool ()
429
+ val session = CanvasSession (pen)
430
+
431
+ println (" Pen color: ${pen.color} " )
432
+ // Pen color: black
433
+
434
+ println (" Session color: ${session.color} " )
435
+ // Session color: blue
436
+
437
+ session.draw(" circle" )
438
+ // Drawing circle with pen in black
439
+
440
+ session.erase(" top-left corner" )
441
+ // Erasing top-left corner with pen tool
442
+
443
+ println (session.getToolInfo())
444
+ // PenTool(color=black)
349
445
}
350
446
```
447
+ {kotlin-runnable="true" id="kotlin-tour-interface-delegation"}
351
448
352
- If you want to, you can also override the behavior of an inherited member function in the ` RedCircle ` class, but now
449
+ If you want to, you can also override the behavior of an inherited member function in the ` CanvasSession ` class, but now
353
450
you don't have to add new lines of code for every inherited member function.
354
451
355
452
For more information, see [ Delegation] ( delegation.md ) .
0 commit comments