在 Dart 中使用 Mixin 为类添加功能

185 阅读2分钟

刚开始学习 Dart ,这是其中一篇笔记。

mixin 是在多重继承中,复用某个类中代码的方法模式。

比如 A、B、C 三个音乐家,A 会弹钢琴和弹吉他,B 会弹钢琴和玩乌克丽丽,C 会玩乌克丽丽和弹吉他。 我们可以定义这样三个类。

class Musician {

}

abstract class Paino {
    void playPaino();
}

abstract class Guita {
    void playGuita();
}

abstract class Ukelele {
    void playUkelele();
}

class A extends Musician implements Paino, Guita {
    void playPaino() {}
    void playGuita() {}
}

class B extends Musician implements Paino, Ukelele {
    void playPaino() {}
    void playUkelele() {}
}

class C extends Musician implements Ukelele, Guita {
    void playUkelele() {}
    void playGuita() {}
}

以上方法可以解决我们的问题,但是又有一个新的问题出来了: 我们将要在每个类中都实现 void playPaino()void playGuita()void playUkelele() 方法。

这样做可能太过麻烦,而且也不符合 DRY 的原则。

有什么其他办法可以将相同的方法抽取出来呢? 这时候 mixin 就登场了。

使用 mixin 关键字来完成上面的需求。

class Musician {

}

mixin GuitaMaster {
    void playGuita() {
        print('guita master');
    }
}

mixin PainoMaster {
    void playPaino() {
        print('paino master');
    }
}

mixin UkeleleMaster {
    void playUkelele() {
        print('ukelele master');
    }
}

mixin PokemonMaster {
    void playPokemonGo() {
        print('pokemon get daze!');
    }
}

class A with GuitaMaster, PainoMaster {

}

class B with PainoMaster, UkeleleMaster {

}

class C with UkeleleMaster, GuitaMaster {

}

注意区别:在 abstract 中我们并没有定义接口的实现逻辑,只是规定实现类中必须实现该方法。

abstract 类中,我们可以实现具体的方法,但当 abstract 类被当作接口来使用时,必须在类中重新实现该方法,而忽略了抽象内中的实现。 abstract 类可以被当作父类使用,所以使用 extends 拓展子类时,抽象内的实现可以被执行。

但是在 mixin 中,我们定义了具体的方法实现。 这样依旧解决我们的需求,而且复用性更强。

此外像上面那样定义 mixin,其实 class 本身也可以被当作 mixin

另外需要注意的是: mixin 必须是直接继承 Object 类的,或者是直接或者间接继承 extends 关键字后面的类。

可以指定 on 关键字,指定哪些类可以被继承。

下面的例子中,只有当被混入的子类拓展于 Musician 类时,才会生效。

class Musician {

}

class Pokemonor {

}

mixin GuitaMaster on Musician {
    void playGuita() {
        print('guita master');
    }
}

mixin PainoMaster on Musician {
    void playPaino() {
        print('paino master');
    }
}

mixin UkeleleMaster on Musician {
    void playUkelele() {
        print('ukelele master');
    }
}

mixin PokemonMaster on Pokemonor {
    void playPokemonGo() {
        print('pokemon get daze!');
    }
}

class A extends Musician with GuitaMaster, PainoMaster {

}

class B extends Musician with PainoMaster, UkeleleMaster {

}

class C extends Musician with UkeleleMaster, GuitaMaster {

}

// 下面这个例子会报错,因为它不继承于 `Musician` 类
class D extends Pokemonor with UkeleleMaster {

}