Mixins

混合(Mixins)是 TypeScript 支持的 JavaScript 类的伪多重继承 模式。该模式允许您创建一个由许多类合并而成的类。 首先我们需要一种类型,用于扩展其他类。主要职责是声明传入的类型是一个类。

type Constructor = new (...args: any[]) => {};

// 然后我们可以创建一系列的类,这些类通过包装最终的类来进行扩展。 此模式当相似的对象具有不同的功能时效果很好。 这个混合添加了 scale 属性,并带有用于使用封装的 private 属性 以及对其进行更改的 getter 和 setter:
function Scale(Base: TBase) {
  return class extends Base {
    private _scale = 1;

    setScale(scale: number) {
      this._scale = scale;
    }

    get scale(): number {
      return this._scale;
    }
  };
}

// 该混合围绕 alpha 合成添加了额外的方法,现代计算机使用这些方法来创建深度:

function Alpha(Base: TBase) {
  return class extends Base {
    private alpha = 1;

    setHidden() {
      this.alpha = 0;
    }

    setVisible() {
      this.alpha = 1;
    }

    setAlpha(alpha: number) {
      this.alpha = alpha;
    }
  };
}

// 一个用于扩展的简单的 sprite 基类:

class Sprite {
  name = "";
  x = 0;
  y = 0;

  constructor(name: string) {
    this.name = name;
  }
}

// 我们将创建两种具有不同功能的 sprite:

const ModernDisplaySprite = Alpha(Scale(Sprite));
const EightBitSprite = Scale(Sprite);

// 创建这些类的实例表明,由于对象的混合,这些对象具有不同的属性和方法:

const flappySprite = new ModernDisplaySprite("Bird");
flappySprite.x = 10;
flappySprite.y = 20;
flappySprite.setVisible();
flappySprite.setScale(0.8);
console.log(flappySprite.scale);

const gameBoySprite = new EightBitSprite("L block");
gameBoySprite.setScale(0.3);

// 由于 EightBitSprite 没有用于更改 alpha 的混合而报错:
gameBoySprite.setAlpha(0.5);

// 如果要对包装的类提供更多的保证,则可以将构造函数与泛型一起使用。

type GConstructor = new (...args: any[]) => T;

// 您可以声明只能在基类为特殊形状时应用此混合。

type Moveable = GConstructor<{ setXYAcceleration: (x: number, y: number) => void }>;

// 然后我们可以创建一个混合,它依赖于上述 GConstructor 参数 中存在的函数。
function Jumpable(Base: TBase) {
  return class extends Base {
    jump() {
      // 这个混合现在可以知道 setXYAcceleration
      this.setXYAcceleration(0, 20);
    }
  };
}

// 只有在混合的结构中有一个添加 setXYAcceleration 的类之后 我们才能创建此 sprite:
const UserSprite = new Jumpable(ModernDisplaySprite);