Composition over inheritance (and Kotlin)

栏目: IT技术 · 发布时间: 6年前

内容简介:Composition over inheritance is the principle that classes should achieve polymorphic behavior and code reuse by their composition (by containing instances of other classes that implement the desired functionality) rather than inheritance from a base or pa

Composition over inheritance is the principle that classes should achieve polymorphic behavior and code reuse by their composition (by containing instances of other classes that implement the desired functionality) rather than inheritance from a base or parent class.

- Wikipedia

In computer science classes you get to learn a ton about inheritance. You study the different programming languages and how they implement inheritance (or multiple inheritance) in the name of polymorphism.

A simple inheritance example is having a base/parent class that many more classes are extending, potentially for more than one level:

open class Parent {
    fun parentFunctionality() {}
}

open class Child(): Parent() {
    fun childFunctionality() {}
}

class Grandchild constructor() : Child() {
    fun grandchildFunctionality() {}
}

An instance of Grandchild will be able to use childFunctionality() and parentFunctionality()

But in real-world software engineering, inheritance is not that desirable. There's even a software engineering principle against inheritance!

The example above would look like this using composition:

open class Parent {
    fun parentFunctionality() {}
}

open class Child() {
    private val parent = Parent()
    
    fun parentFunctionality() { parent.parentFunctionality() }
    fun childFunctionality() {}
}

class Grandchild  {
    private val parent = Parent()
    private val child = Child()

    fun parentFunctionality() { parent.parentFunctionality() }
    fun childFunctionality() { child.childFunctionality() }
    fun grandchildFunctionality() {}
}

But why follow this pattern when it's more verbose? And when should someone prefer composition over inheritance? Should we avoid it at all times?

There are plenty of advantages for going with composition:

  • Testability : You just swipe the real implementation with the fake one. Especially convenient with a dependency injection framework.
  • Maintainability : Multilevel inheritance can make the code hard to read and comprehend, especially for people unfamiliar with the codebase. Composition is simpler, but maybe a bit more verbose.

Kotlinprovides some feature to make composition easier:

  • Objects : Essentially they are singleton values defined with their own keyword. The first time they are used an instance will be created and all the following invocations will use the same (single) instance. Especially useful if you do not use a dependency injection framework and you need singleton instances around your app.
object Parent {
    fun parentFunctionality() {}
}

object Child {
    private val parent = Parent
  
	[...]
	fun childFunctionality() {}
}

object Grandchild  {
    private val parent = Parent
    private val child = Child 
    
	[...]
	fun grandchildFunctionality() {}
}
  • Lazy : Useful if you want an instance only the first time a property is used. All the following invocations will use the instance that was created the first time.
open class Parent {
    fun parentFunctionality() {}
}

open class Child() {
    val parent by lazy { Parent() }

	[...]
    fun childFunctionality() {}
}

class Grandchild {
    val parent by lazy { Parent() }
    val child by lazy { Child() }

	[...]
    fun grandchildFunctionality() {}
}
  • Extension methods : Not exactly composition, but can be used in the place of inheritance. This is for "virtually" extending a class, even if it's not allowed (e.g. Android system classes).
class SystemClass {
	[...]
}

fun SystemClass.newFunctionality() {}

SystemClass().newFunctionality()

Still, I think there are cases that inheritance should be used instead of composition:

  • If you only need 1 level of inheritance, it's easier (and more readable) than composition. When you need more levels, maybe you should switch to composition.
  • When you need to implement an interface, you have to use inheritance. The rule that you should try is to implement "interface inheritance", rather the "functional inheritance". Try to "inherit" functionality using composition.

Happy coding with more readable code! (what "readable" means is a discussion for another post :)


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

第二次机器革命

第二次机器革命

[美]埃里克·布莱恩约弗森 / 蒋永军 / 中信出版社 / 2014-9 / 59.80

“一本非常鼓舞人心的书!”——托马斯•L•弗里德曼 《世界是平的》作者 一场革命开始了! 在《第二次机器革命》这本书中,埃里克•布莱恩约弗森和安德鲁•麦卡菲——这两位处于数字技术时代最前沿的思想家,向我们阐述了驱动我们经济和生活的发生变革的力量。他们认为,数字技术将会给我们带来难以想象的巨大变革:想象一下令人眩目的个人数字技术产品、一流的基础设施,都将会给我们带来极大的便利。数字技术(......一起来看看 《第二次机器革命》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具