Mixins

混入 (Mixins)

介绍

除了传统的OO层次结构之外,另一种从可重用组件构建类的流行方式是通过组合更简单的部分类来构建它们。您可能熟悉Scala等语言的mixins或traits的概念,并且该模式在 JavaScript 社区中也已经广受欢迎。

混合样品

在下面的代码中,我们展示了如何在 TypeScript 中为 mixin 建模。在代码之后,我们将分解它的工作原理。

// Disposable Mixin class Disposable { isDisposed: boolean; dispose() { this.isDisposed = true; } } // Activatable Mixin class Activatable { isActive: boolean; activate() { this.isActive = true; } deactivate() { this.isActive = false; } } class SmartObject implements Disposable, Activatable { constructor() { setInterval(() => console.log(this.isActive + " : " + this.isDisposed), 500 } interact() { this.activate( } // Disposable isDisposed: boolean = false; dispose: () => void; // Activatable isActive: boolean = false; activate: () => void; deactivate: () => void; } applyMixins(SmartObject, [Disposable, Activatable] let smartObj = new SmartObject( setTimeout(() => smartObj.interact(), 1000 //////////////////////////////////////// // In your runtime library somewhere //////////////////////////////////////// function applyMixins(derivedCtor: any, baseCtors: any[]) { baseCtors.forEach(baseCtor => { Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => { derivedCtor.prototype[name] = baseCtor.prototype[name]; } } }

了解样本

代码示例以两个类作为我们的 mixin 开始。你可以看到每一个都专注于一个特定的活动或能力。我们稍后将把它们混合在一起,从这两种能力中形成一个新课堂。

// Disposable Mixin class Disposable { isDisposed: boolean; dispose() { this.isDisposed = true; } } // Activatable Mixin class Activatable { isActive: boolean; activate() { this.isActive = true; } deactivate() { this.isActive = false; } }

接下来,我们将创建将处理两个 mixin 组合的类。让我们更详细地看看它是如何做到这一点的:

class SmartObject implements Disposable, Activatable {

您在上面可能会注意到的第一件事是extends,我们使用而不是使用implements。这将类视为接口,仅使用 Disposable 和 Activatable 后面的类型,而不是实现。这意味着我们必须在课堂上提供实施。除此之外,这正是我们想要通过使用 mixin 避免的。

为了满足这个要求,我们为来自我们的 mixin 的成员创建替代属性及其类型。这满足了编译器,这些成员将在运行时可用。这让我们仍然可以从 mixins 中获益,尽管存在一些簿记开销。

// Disposable isDisposed: boolean = false; dispose: () => void; // Activatable isActive: boolean = false; activate: () => void; deactivate: () => void;

最后,我们将 mixin 混合到课堂中,创建完整的实现。

applyMixins(SmartObject, [Disposable, Activatable]

最后,我们创建一个辅助函数,为我们做混音。这将贯穿每个 mixin 的属性,并将它们复制到 mixin 的目标中,并使用它们的实现填充 stand-in 属性。

function applyMixins(derivedCtor: any, baseCtors: any[]) { baseCtors.forEach(baseCtor => { Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => { derivedCtor.prototype[name] = baseCtor.prototype[name]; } } }