• 混合
    • 关于混合的例子
    • 理解例子

    混合

    在使用传统的面向对象语言时,一个基于类构建可重用组件的办法是,让一个类基于多个简单的类。你可能对Scala语言中“混合”的概念有所知晓。类似的概念如今在JavaScript社区中也越来越流行。

    关于混合的例子

    下面的例子展示了TypeScript中的混合:

    1. // Disposable Mixin
    2. class Disposable {
    3. isDisposed: boolean;
    4. dispose() {
    5. this.isDisposed = true;
    6. }
    7. }
    8. // Activatable Mixin
    9. class Activatable {
    10. isActive: boolean;
    11. activate() {
    12. this.isActive = true;
    13. }
    14. deactivate() {
    15. this.isActive = false;
    16. }
    17. }
    18. class SmartObject implements Disposable, Activatable {
    19. constructor() {
    20. setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500);
    21. }
    22. interact() {
    23. this.activate();
    24. }
    25. // Disposable
    26. isDisposed: boolean = false;
    27. dispose: () => void;
    28. // Activatable
    29. isActive: boolean = false;
    30. activate: () => void;
    31. deactivate: () => void;
    32. }
    33. applyMixins(SmartObject, [Disposable, Activatable])
    34. var smartObj = new SmartObject();
    35. setTimeout(() => smartObj.interact(), 1000);
    36. ////////////////////////////////////////
    37. // In your runtime library somewhere
    38. ////////////////////////////////////////
    39. function applyMixins(derivedCtor: any, baseCtors: any[]) {
    40. baseCtors.forEach(baseCtor => {
    41. Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
    42. derivedCtor.prototype[name] = baseCtor.prototype[name];
    43. })
    44. });
    45. }

    理解例子

    上文的例子以两个类开始,这两个类专注于各自的活动和功能。在后面我们将它们混合入一个新类来同时获取它们两个的功能。

    1. // Disposable Mixin
    2. class Disposable {
    3. isDisposed: boolean;
    4. dispose() {
    5. this.isDisposed = true;
    6. }
    7. }
    8. // Activatable Mixin
    9. class Activatable {
    10. isActive: boolean;
    11. activate() {
    12. this.isActive = true;
    13. }
    14. deactivate() {
    15. this.isActive = false;
    16. }
    17. }

    然后,我们将这个类混合入了一个新类,让我们仔细看看它的语法:

    1. class SmartObject implements Disposable, Activatable {

    你可能很快注意到,我们并没有使用extends关键字,而是使用了implements。这会将类视为接口,然后只使用DisposableActivatable这两个类背后的类型声明,而不是具体实现。这意味着在后面,我们需要自己在类中提供实现细节。这可能并不是我们喜欢做的。

    为了不重新提供实现细节,我们创建了同名属性,并且提供了同样的类型。这会告诉编译器这些成员在运行时将会可用,这将让我们不用机械地重新抄写一遍同样的代码:

    1. // Disposable
    2. isDisposed: boolean = false;
    3. dispose: () => void;
    4. // Activatable
    5. isActive: boolean = false;
    6. activate: () => void;
    7. deactivate: () => void;

    最后,我们将其混合入类中,补全了具体的实现:

    1. applyMixins(SmartObject, [Disposable, Activatable])

    applyMixins是我们创建的一个辅助函数。这将会遍历我们被混合的类的原型,将其的具体实现赋值给最终类:

    1. function applyMixins(derivedCtor: any, baseCtors: any[]) {
    2. baseCtors.forEach(baseCtor => {
    3. Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
    4. derivedCtor.prototype[name] = baseCtor.prototype[name];
    5. })
    6. });
    7. }