我试图通过在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?那么模拟抽象方法呢,我可以保护那些仍然可以调用超级方法吗?
答案 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);
}
}