应该多用组合, 而不要无脑继承. Favor composition over inheritance
为什么? 因为使用继承后, 比如 B 继承 A, 那么 B 跟 A 之间的关系就定死了, 是"is a"
的关系. 而使用组合则更灵活, B 可以委托 A, 也可以委托 A 的子类, 只要是 A 类型的就
可以了. 看下面的 java 例子:
建立委托关系, 经理委托司机开车
public class DelegateDemo1 {
public static void main(String[] args) {
Driver d = new Driver();
Manager m = new Manager(d);
m.drive(); // 会输出 Driver driving
}
}
class Driver {
public void drive() {
System.out.println("Driver driving");
}
}
class Manager {
private Driver driver; // 建立委托关系
Manager(Driver driver) {
this.driver = driver;
}
public void drive() {
driver.drive(); // 经理委托司机开车
}
}
经理对这位司机不满意, 还可以委托老司机开车:
class OlderDriver extends Driver {
@Override
public void drive() {
System.out.println("老司机开车...");
}
}
public class DelegateDemo1 {
public static void main(String[] args) {
// Driver d = new Driver();
// Manager m = new Manager(d);
Driver old = new OlderDriver();
Manager m = new Manager(old);
m.drive();
}
}
这时候输出的是 老司机开车...
使用接口方式的委托模式是同理的:
public class DelegateDemo1 {
public static void main(String[] args) {
new D(new B()).say(); // 打印 B says ...
new D(new C()).say(); // 打印 C says ...
}
}
interface Ia {
void say();
}
class B implements Ia {
@Override
public void say() {
System.out.println("B says ...");
}
}
class C implements Ia {
@Override
public void say() {
System.out.println("C says ...");
}
}
class D implements Ia {
private Ia delegator; // 建立委托关系
D(Ia ia) {
this.delegator = ia;
}
@Override
public void say() {
delegator.say();
}
}
Kotlin 中为了限制你使用继承, class 都默认是 final
的, 懂了吧.
Java 中委托模式(代理模式) 就是应用了组合的思想.
Kotlin 从语言层面实现了"委托", 使用 by
关键字即可. 委托也可以用于属性, 但是这
节我们只讲"类委托". 上面的代码用 Kotlin 重写的话是这样的:
interface Drivable {
fun drive()
}
class Driver: Drivable {
override fun drive() = println("Driver driving ...")
}
class OlderDriver: Drivable {
override fun drive() {
println("老司机开车...")
}
}
class Manager(driver: Drivable): Drivable by driver
fun main(args: Array<String>) {
Manager(Driver()).drive() // Driver driving ...
Manager(OlderDriver()).drive() // 老司机开车...
}
Kotlin 中使用只有接口才能用 by
代理, 所以我们写了一个 Drivable
接口.
对于 Manager
类来说, driver: Drivable
是代理字段, Kotlin 会自动生成一个代理
字段(类似 $$delegate_0
). 所以写 var
val
是无意义的. 当然, 写上也没问题,
这样会生成 driver
backing field 以及 getter setter 方法.
Manager
反编译为 Java 代码后的样子:
public final class Manager implements Drivable {
// $FF: synthetic field
private final Drivable $$delegate_0;
public Manager(@NotNull Drivable driver) {
Intrinsics.checkParameterIsNotNull(driver, "driver");
super();
this.$$delegate_0 = driver;
}
public void drive() {
this.$$delegate_0.drive();
}
}
使用多个 by
也是可以的:
interface Nameable {
var name: String
}
class JackName : Nameable {
override var name: String = "Jack"
}
class LongDistanceRunner: Runnable {
override fun run() {
println("long")
}
}
class Person(name: Nameable, runner: Runnable): Nameable by name, Runnable by runner
fun main(args: Array<String>) {
val person = Person(JackName(), LongDistanceRunner())
println(person.name) //Jack
person.run() //long
}