如何模拟抽象类并调用其构造函数?

时间:2014-07-18 04:16:05

标签: oop design-patterns typescript

我试图通过在TypeScript中编写代码来跟随C#设计模式书。也许这是我的第一个错误,但这是我学习语言的一种方式。

TypeScript不支持类的abstract关键字,所以我试图模拟它。也许这是我的第二个错误。

这是我的界面和类:

interface IEngine {
  getSize(): number;
  getTurbo(): boolean;
}

class AbstractEngine implements IEngine {
  constructor(private size: number, private turbo: boolean) {
    throw "Abstract class";
  }

  public getSize(): number {
    return this.size;
  }

  public getTurbo(): boolean {
    return this.turbo;
  }

  public toString(): string {
    var funcNameRegex = /function (.{1,})\(/;
    var results = (funcNameRegex).exec(this.constructor.toString());
    var className = (results && results.length > 1) ? results[1] : '';
    return className + " (" + this.size + ")";
  }
}

class StandardEngine extends AbstractEngine {
  constructor(size: number) {
    // not turbo charged
    super(size, false);
  }
}

尝试使用new AbstractEngine(1, true)实例化AbstractEngine时,我得到了一个“抽象类”错误。

尝试使用new StandardEngine(9000)实例化StandardEngine时,我也会收到“抽象类”错误。

有没有办法可以在TypeScript中模拟抽象类,让它无法实例化,但仍然可以在扩展它的类中调用super?那么模拟抽象方法呢,我可以保护那些仍然可以调用超级方法吗?

3 个答案:

答案 0 :(得分:5)

截至今天,TypeScript 1.6 is live并且支持abstract关键字。

abstract class A {
  foo(): number { return this.bar(); }
  abstract bar(): number;
}

var a = new A();  // error, Cannot create an instance of the abstract class 'A'

class B extends A {
  bar() { return 1; }
}

var b = new b();  // success, all abstracts are defined

答案 1 :(得分:1)

我建议你不要这样做。当TypeScript编译器实现抽象函数的机制时,是时候使用它了。但是在运行时工作的黑客是不可理解的并且会降低性能。

接口是TypeScript的强大功能。它们应该被大量使用。

你的例子应该是这样写的:

interface Engine {
  getSize(): number;
  getTurbo(): boolean;
}

class StandardEngine implements Engine {
  constructor(private size: number, private turbo: boolean) {
  }
  public getSize(): number {
    return this.size;
  }
  public getTurbo(): boolean {
    return this.turbo;
  }
}

最简单的解决方案往往是最好的。

如果您想重用没有父类的代码,那么必然可以使用Handbook suggests Mixins。 Mixins是一种应对来自几个不同实体的技能的方式。

或者使用模块可以保持私有实现(因此可以根据需要进行组织)并仅导出接口和工厂。一个例子:

module MyEngineModule {
  export interface Engine {
    getSize(): number;
    getTurbo(): boolean;
  }
  export interface StandardEngine extends Engine {
  }
  export function makeStandardEngine(size: number, turbo: boolean): StandardEngine {
    return new ImplStandardEngine(size, turbo);
  }
  // here classes are private and can inherit or use mixins…
  class ImplEngine {
    constructor(private size: number, private turbo: boolean) {
    }
    public getSize(): number {
      return this.size;
    }
    public getTurbo(): boolean {
      return this.turbo;
    }
  }
  class ImplStandardEngine extends ImplEngine implements StandardEngine {
  }
}
console.log(MyEngineModule.makeStandardEngine(123, true).getSize());

答案 2 :(得分:0)

拨打StandardEngine constructor时,您可以拨打super(size, false)。这种对基类的调用是生成第二个“抽象类”错误的原因。

要模拟在实例化时抛出的抽象基类,请创建一个从派生类调用的Init函数。

class AbstractEngine implements IEngine {
  private _size: number;
  private _turbo: boolean;
  constructor() {
    throw "Abstract class";
  }
  init(size:number, turbo: boolean) {
    this._size = size;
    this._turbo = turbo;
  }
}

class StandardEngine extends AbstractEngine {
  constructor(size: number) {
    // not turbo charged
    // do not call super here
    init(size, false);
  }
}