2014-07-18 5 views
6

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); 
    } 
} 

예상대로 내가 "추상 클래스입니다"오류가 new AbstractEngine(1, true)과 AbstractEngine를 인스턴스화하려고합니다.

new StandardEngine(9000)으로 StandardEngine을 인스턴스화하려고하면 "추상 클래스"오류가 발생합니다.

TypeScript에서 추상 클래스를 시뮬레이트 할 수있는 방법이 있습니까? 인스턴스화 할 수 없지만 확장하는 클래스에서 여전히 super를 호출 할 수 있습니까? 그리고 추상적 인 메소드를 시뮬레이트하는 것은 어떨까요? 나는 그것을 보호 할 수 있습니까? 여전히 슈퍼 메소드를 호출 할 수 있습니까?

답변

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. 믹스 인은 여러 다른 실체의 스킬을 극복하는 방법입니다.

또는 모듈을 사용하여 개인 구현을 유지 (따라서 원하는대로 구성)하고 인터페이스와 팩토리 만 내보낼 수 있습니다. 예 :

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()); 
+0

그러나 StandardEngine뿐만 아니라 여러 가지 구체적인 클래스에 걸쳐 AbstractEngine의 구현을 공유 할 수 있어야합니다. 미안하다. 나는 그 사실을 내 포스트에서 분명히하지 않았다. 나는 당신의 솔루션이 그것을 어떻게 달성 하는지를 보지 못합니다. * 편집 * 아, 신경 쓰지 마세요, 여러 구체적인 수업에 걸쳐 코드를 공유하는 믹스 인에 대해 언급했습니다. 나는 그것을 시도해야 할 것이다. – brycedarling

+0

mixins을 사용하여 이것을 구현 한 후에, StandardEngine과 TurboEngine 클래스에 얼마나 많은 코드를 복사해야하는지 조금 실망했습니다. 이 문제를 해결하고 applyMixins 또는 추상 클래스 또는 둘 다를 호출해야하는 필요성을 제거한 키워드가 있었으면합니다. – brycedarling

+0

또한 상속을 사용했을 때처럼 "StandardEngine"또는 "TurboEngine"대신 mixin으로 구현 될 때 엔진의 사용자 정의 toString 메소드는 항상 클래스 이름으로 "Engine"을 인쇄합니다. – brycedarling

0

StandardEngine constructor으로 전화 할 경우 super(size, false)으로 전화해야합니다. 이 기본 클래스에 대한 호출은 두 번째 "추상 클래스"오류를 생성합니다.

인스턴스 생성시 throw되는 추상 기본 클래스를 시뮬레이트하려면 파생 클래스에서 호출되는 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); 
    } 
} 
+1

StandardEngine에서 super 호출을 생략하면 "생성자 클래스의 생성자에 'super'호출이 있어야합니다."오류가 발생합니다.코드를 시도 할 때 "this"한정자가 없어서 "init '기호를 찾을 수 없습니다."라는 오류 메시지가 나타납니다. – brycedarling

0

대체 솔루션은 사용자가 생성자가 하위 클래스에서 호출되었음을 나타내면 설정을 계속 진행하는 것이 안전하다는 것을 나타내는 속성입니다. 아래에 그 예가 나와 있습니다 :

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); 
    } 
} 
+0

이 코드를 사용해 보았을 때 StandardEngine을 인스턴스화 할 때 Abstract 클래스에 대한 오류가 발생했습니다. 나는 그 아이디어를 이해하지만 구현은 효과가없는 것처럼 보인다. – brycedarling

+0

@brycedarling 오류를 수정했습니다. 그렇지 않으면 하위 값이 덮어 쓰기됩니다. :) – basarat

5
오늘로

, TypeScript 1.6 is liveabstract 키워드에 대한 지원을하고있다.

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 
관련 문제