IT이야기

Typescript : 두 클래스를 확장하는 방법

cyworld 2021. 4. 20. 21:41
반응형

Typescript : 두 클래스를 확장하는 방법은 무엇입니까?


시간을 절약하고 PIXI 클래스 (2d webGl 렌더러 라이브러리)를 확장하는 클래스간에 공통 코드를 재사용하고 싶습니다.

개체 인터페이스 :

module Game.Core {
    export interface IObject {}

    export interface IManagedObject extends IObject{
        getKeyInManager(key: string): string;
        setKeyInManager(key: string): IObject;
    }
}

내 문제는 코드 내부에 있다는 것입니다 getKeyInManagersetKeyInManager변경되지 않습니다 내가하지 그것을 복제, 재사용하려면, 여기 구현은 다음과 같습니다

export class ObjectThatShouldAlsoBeExtended{
    private _keyInManager: string;

    public getKeyInManager(key: string): string{
        return this._keyInManager;
    }

    public setKeyInManager(key: string): DisplayObject{
        this._keyInManager = key;
        return this;
    }
}

내가하고 싶은 Manager.add()것은 관리자에서 사용되는 키를 통해 자동으로 추가 하여 속성에서 개체 자체 내부 의 개체 를 참조하는 것입니다 _keyInManager.

자, 텍스처로 예를 들어 보겠습니다. 여기에 간다TextureManager

module Game.Managers {
    export class TextureManager extends Game.Managers.Manager {

        public createFromLocalImage(name: string, relativePath: string): Game.Core.Texture{
            return this.add(name, Game.Core.Texture.fromImage("/" + relativePath)).get(name);
        }
    }
}

내가 할 때 this.add(), 내가 원하는 Game.Managers.Manager add()방법은 개체에 의해 반환에 존재하는 것 메소드를 호출 Game.Core.Texture.fromImage("/" + relativePath). 이 경우이 객체는 다음과 Texture같습니다.

module Game.Core {
    // I must extends PIXI.Texture, but I need to inject the methods in IManagedObject.
    export class Texture extends PIXI.Texture {

    }
}

나는 그것이 IManagedObject인터페이스이고 구현을 포함 할 수 없다는 것을 알고 있지만 클래스 ObjectThatShouldAlsoBeExtended내부 에 클래스를 주입하기 위해 무엇을 작성해야할지 모르겠습니다 Texture. 동일한 프로세스가 요구 될 것이라는 점을 알고 Sprite, TilingSprite, Layer등.

경험이 풍부한 TypeScript 피드백 / 조언이 여기에 필요합니다. 가능해야하지만 한 번에 하나만 가능하므로 여러 확장으로 확장 할 수 없습니다. 다른 솔루션을 찾지 못했습니다.


Mixins를 사용하여 재사용 가능한 작은 개체를 만들 수있는 TypeScript에는 약간 알려진 기능이 있습니다. 다중 상속을 사용하여이를 더 큰 객체로 구성 할 수 있습니다 (클래스에는 다중 상속이 허용되지 않지만 믹스 인에는 허용됩니다. 이는 관련 표현이있는 인터페이스와 같습니다).

TypeScript Mixins에 대한 추가 정보

이 기술을 사용하여 게임의 여러 클래스간에 공통 구성 요소를 공유하고 게임의 단일 클래스에서 이러한 구성 요소를 많이 재사용 할 수 있습니다.

다음은 간단한 Mixins 데모입니다 ... 먼저 혼합하려는 맛 :

class CanEat {
    public eat() {
        alert('Munch Munch.');
    }
}

class CanSleep {
    sleep() {
        alert('Zzzzzzz.');
    }
}

그런 다음 Mixin 생성을위한 마법의 방법 (프로그램 어딘가에 한 번만 필요합니다 ...)

function applyMixins(derivedCtor: any, baseCtors: any[]) {
    baseCtors.forEach(baseCtor => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
             if (name !== 'constructor') {
                derivedCtor.prototype[name] = baseCtor.prototype[name];
            }
        });
    }); 
}

그런 다음 mixin 풍미에서 다중 상속을 사용하여 클래스를 만들 수 있습니다.

class Being implements CanEat, CanSleep {
        eat: () => void;
        sleep: () => void;
}
applyMixins (Being, [CanEat, CanSleep]);

이 클래스에는 실제 구현이 없습니다. "인터페이스"의 요구 사항을 통과하기에 충분합니다. 그러나이 클래스를 사용하면 모든 것이 작동합니다.

var being = new Being();

// Zzzzzzz...
being.sleep();

https://blogs.msdn.microsoft.com/typescript/2017/02/22/announcing-typescript-2-2/에 설명 된 새로운 믹스 인 접근 방식을 사용하는 것이 좋습니다.

이 접근 방식은 Fenton이 설명한 "applyMixins"접근 방식보다 낫습니다. 자동 컴파일러가 기본 및 두 번째 상속 클래스의 모든 메서드 / 속성을 표시하고 도움을주기 때문입니다.

이 접근 방식은 TS 플레이 그라운드 사이트 에서 확인할 수 있습니다 .

구현은 다음과 같습니다.

class MainClass {
    testMainClass() {
        alert("testMainClass");
    }
}

const addSecondInheritance = (BaseClass: { new(...args) }) => {
    return class extends BaseClass {
        testSecondInheritance() {
            alert("testSecondInheritance");
        }
    }
}

// Prepare the new class, which "inherits" 2 classes (MainClass and the cass declared in the addSecondInheritance method)
const SecondInheritanceClass = addSecondInheritance(MainClass);
// Create object from the new prepared class
const secondInheritanceObj = new SecondInheritanceClass();
secondInheritanceObj.testMainClass();
secondInheritanceObj.testSecondInheritance();

불행히도 typescript는 다중 상속을 지원하지 않습니다. 따라서 완전히 사소한 대답은 없으며 프로그램을 재구성해야 할 것입니다.

다음은 몇 가지 제안입니다.

  • 이 추가 클래스에 많은 하위 클래스가 공유하는 동작이 포함되어있는 경우 클래스 계층의 맨 위 어딘가에 삽입하는 것이 좋습니다. 이 클래스에서 Sprite, Texture, Layer, ...의 공통 수퍼 클래스를 파생시킬 수 있습니까? hirarchy 유형에서 좋은 자리를 찾을 수 있다면 이것은 좋은 선택이 될 것입니다. 그러나이 클래스를 임의의 지점에 삽입하는 것은 권장하지 않습니다. 상속은 "Is a-관계"를 표현합니다. 예를 들어 개는 동물이고 텍스처는이 클래스의 인스턴스입니다. 이것이 실제로 코드의 객체 간의 관계를 모델링하는지 스스로에게 물어봐야합니다. 논리적 상속 트리는 매우 중요합니다.

  • 추가 클래스가 유형 계층 구조에 논리적으로 맞지 않는 경우 집계를 사용할 수 있습니다. 즉,이 클래스 유형의 인스턴스 변수를 Sprite, Texture, Layer, ...의 공통 수퍼 클래스에 추가하면 모든 하위 클래스에서 getter / setter를 사용하여 변수에 액세스 할 수 있습니다. 이것은 "관계 있음"을 모델링합니다.

  • 클래스를 인터페이스로 변환 할 수도 있습니다. 그런 다음 모든 클래스로 인터페이스를 확장 할 수 있지만 각 클래스에서 메서드를 올바르게 구현해야합니다. 이것은 약간의 코드 중복을 의미하지만이 경우에는 많지 않습니다.

어떤 접근 방식을 가장 좋아하는지 스스로 결정해야합니다. 개인적으로 클래스를 인터페이스로 변환하는 것이 좋습니다.

한 가지 팁 : Typescript는 getter 및 setter를위한 구문 설탕 인 속성을 제공합니다. http://blogs.microsoft.co.il/gilf/2013/01/22/creating-properties-in-typescript/를 살펴보십시오.


데코레이터라는 JavaScript (ES7)의 새로운 기능이 있으며,이 기능과 typescript-mix 라는 작은 라이브러리 를 사용하면 믹스 인 을 사용하여 단 몇 줄로 다중 상속을 할 수 있습니다.

// The following line is only for intellisense to work
interface Shopperholic extends Buyer, Transportable {}

class Shopperholic {
  // The following line is where we "extend" from other 2 classes
  @use( Buyer, Transportable ) this 
  price = 2000;
}

확실한 유형 안전성 과 확장 성 을 허용하는 훨씬 더 나은 접근 방식이 있다고 생각 합니다.

먼저 대상 클래스에서 구현하려는 인터페이스를 선언하십시오.

interface IBar {
  doBarThings(): void;
}

interface IBazz {
  doBazzThings(): void;
}

class Foo implements IBar, IBazz {}

이제 Foo클래스에 구현을 추가해야합니다 . 다음 인터페이스도 구현하는 클래스 믹스 인을 사용할 수 있습니다.

class Base {}

type Constructor<I = Base> = new (...args: any[]) => I;

function Bar<T extends Constructor>(constructor: T = Base as any) {
  return class extends constructor implements IBar {
    public doBarThings() {
      console.log("Do bar!");
    }
  };
}

function Bazz<T extends Constructor>(constructor: T = Base as any) {
  return class extends constructor implements IBazz {
    public doBazzThings() {
      console.log("Do bazz!");
    }
  };
}

Foo클래스 믹스 인으로 클래스 확장 :

class Foo extends Bar(Bazz()) implements IBar, IBazz {
  public doBarThings() {
    super.doBarThings();
    console.log("Override mixin");
  }
}

const foo = new Foo();
foo.doBazzThings(); // Do bazz!
foo.doBarThings(); // Do bar! // Override mixin

참조 URL : https://stackoverflow.com/questions/26948400/typescript-how-to-extend-two-classes

반응형