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

bry*_*ing 6 oop design-patterns typescript

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

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

这是我的界面和类:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试实例化AbstractEngine时,new AbstractEngine(1, true)我得到了一个"抽象类"错误.

当我尝试用new StandardEngine(9000)我实例化StandardEngine时,我也得到一个"抽象类"错误.

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

Fen*_*ton 5

截至今天,TypeScript 1.6已经上线,并且支持该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
Run Code Online (Sandbox Code Playgroud)


Pal*_*leo 1

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

\n\n

界面是 TypeScript 的强大优势。它们应该被大量使用。

\n\n

你的例子应该这样写:

\n\n
interface Engine {\n  getSize(): number;\n  getTurbo(): boolean;\n}\n\nclass StandardEngine implements Engine {\n  constructor(private size: number, private turbo: boolean) {\n  }\n  public getSize(): number {\n    return this.size;\n  }\n  public getTurbo(): boolean {\n    return this.turbo;\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

如果您想在没有父类的情况下重用代码,那么该代码必然可用,手册建议使用 Mixins。Mixin 是一种应对来自多个不同实体的技能的方法。

\n\n

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

\n\n
module MyEngineModule {\n  export interface Engine {\n    getSize(): number;\n    getTurbo(): boolean;\n  }\n  export interface StandardEngine extends Engine {\n  }\n  export function makeStandardEngine(size: number, turbo: boolean): StandardEngine {\n    return new ImplStandardEngine(size, turbo);\n  }\n  // here classes are private and can inherit or use mixins\xe2\x80\xa6\n  class ImplEngine {\n    constructor(private size: number, private turbo: boolean) {\n    }\n    public getSize(): number {\n      return this.size;\n    }\n    public getTurbo(): boolean {\n      return this.turbo;\n    }\n  }\n  class ImplStandardEngine extends ImplEngine implements StandardEngine {\n  }\n}\nconsole.log(MyEngineModule.makeStandardEngine(123, true).getSize());\n
Run Code Online (Sandbox Code Playgroud)\n