Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 如何模拟抽象类并调用其构造函数?_Oop_Design Patterns_Typescript - Fatal编程技术网

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

Oop 如何模拟抽象类并调用其构造函数?,oop,design-patterns,typescript,Oop,Design Patterns,Typescript,我正试图通过用TypeScript编写代码来遵循一本C#design patterns的书。也许这是我的第一个错误,但这是我喜欢学习语言的一种方式 TypeScript不支持类的抽象关键字,所以我尝试模拟它。也许这是我的第二个错误 以下是我的界面和类: interface IEngine { getSize(): number; getTurbo(): boolean; } class AbstractEngine implements IEngine { constructor(

我正试图通过用TypeScript编写代码来遵循一本C#design patterns的书。也许这是我的第一个错误,但这是我喜欢学习语言的一种方式

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);
  }
}
当尝试用
新的AbstractEngine(1,true)
实例化AbstractEngine时,我得到了预期的“抽象类”错误

当尝试用
新标准引擎(9000)
实例化标准引擎时,我还得到一个“抽象类”错误


有没有一种方法可以在TypeScript中模拟一个抽象类,让它无法实例化,但仍然在一个扩展它的类中调用super?模拟抽象方法怎么样,我可以保护这些方法并仍然调用super方法吗?

当调用
标准引擎构造函数时,您可以调用
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);
  }
}

另一种解决方案是使用一个属性,如果set指示正在从子类调用构造函数,则可以安全地继续。如下所示:

class AbstractEngine {
  safe; // IMPORTANT : do not initialize
  constructor(private size: number, private turbo: boolean) {
    if(!this.safe) throw "Abstract class"; // IMPORTANT
  }    

}

class StandardEngine extends AbstractEngine {  
  constructor(size: number) {       
    this.safe = true; // IMPORTANT
    super(size, false);
  }
}

我劝你不要那样做。当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;
  }
}
最简单的解决方案往往是最好的

如果您想在没有父类的情况下重用代码,那么就必须使用。混血是一种应对来自几个不同实体的技能的方法

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

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());
从今天起,已支持
摘要
关键字

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

但我需要能够在AbstractEngine中跨几个不同的具体类共享实现,而不仅仅是StandardEngine。很抱歉,我没有在我的帖子里说得那么明显。我看不出您的解决方案如何帮助实现这一点。编辑啊,没关系,我看到你提到了关于mixin的部分,这将实现跨多个具体类共享代码。我必须试一试。在使用mixin实现了这一点之后,我有点失望,因为我不得不将大量代码复制到StandardEngine和TurboEngine类。我希望有一个关键字能够解决这个问题,并消除调用applyMixins或抽象类或两者的必要性。此外,引擎上的自定义toString方法在实现为mixin时总是为类名打印“Engine”,而不是像使用继承时那样的“StandardEngine”或“TurboEngine”。我同意,混血儿缺乏优雅。它们是原型中的手动操作,而且不干燥。我建议您使用最后一种解决方案。在模块中,使用继承创建私有类。例如,ImplEngine← 安装标准发动机。从模块外部,ImplEngine将不会实例化。如果我在StandardEngine中忽略对super的调用,则会出现错误“派生类的构造函数必须包含“super”调用”。在尝试您的代码时,我还收到错误“找不到符号'init'”,因为它缺少“this”限定符。当我尝试此代码时,在实例化StandardEngine时,我仍然收到针对抽象类抛出的错误。我理解这个想法,但实现似乎不起作用。@Bryce,我纠正了错误。基类不应设置该值,否则子值将被覆盖:)