programing

타이프스크립트:어떻게 하면 두 개의 수업을 연장할 수 있을까요?

oldcodes 2023. 2. 23. 23:04
반응형

타이프스크립트:어떻게 하면 두 개의 수업을 연장할 수 있을까요?

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

오브젝트 인터페이스:

module Game.Core {
    export interface IObject {}

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

는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★getKeyInManager ★★★★★★★★★★★★★★★★★」setKeyInManager변경되지 않습니다.복제가 아닌 재사용하고 싶습니다.실장 내용은 다음과 같습니다.

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 extend PIXI.Texture, but I need to inject the methods in IManagedObject.
    export class Texture extends PIXI.Texture {

    }
}

는 그것을 있다.IManagedObject할 수 만, 무엇을 ObjectThatShouldAlsoBeExtended 안에Texture을 알고 있습니다.Sprite,TilingSprite,Layer기타 등등.

여기에 경험이 풍부한 TypeScript 피드백/조언은 필요합니다.그것은 가능해야 합니다만, 동시에 가능한 것은 1개뿐이기 때문에 여러 번 연장할 수 없습니다.다른 해결책을 찾을 수 없었습니다.

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

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 Playground 사이트에서 확인할 수 있습니다.

실장은 다음과 같습니다.

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

https://www.npmjs.com/package/ts-mixer의 최신 비길 데 없는 솔루션을 찾았습니다.

천만에요 :)

TypeScript는 데코레이터를 지원하며, 이 기능과 typescript-mix라는 작은 라이브러리를 사용하여 mixins를 사용하여 몇 줄의 행만으로 여러 개의 상속을 수행할 수 있습니다.

// 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'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE:

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

안타깝게도 typescript는 다중 상속을 지원하지 않습니다.따라서 완전히 사소한 답변은 없습니다.아마 프로그램을 재구성해야 할 것입니다.

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

  • 이 추가 클래스에 많은 서브클래스가 공유하는 동작이 포함되어 있는 경우 클래스 계층에 최상위 클래스 계층에 삽입하는 것이 좋습니다.아마도 당신은 이 클래스에서 사이다, 텍스처, 레이어 등의 공통 슈퍼클래스를 도출할 수 있을 것이다.만약 당신이 히라시 타입에서 좋은 자리를 찾을 수 있다면, 이것은 좋은 선택이 될 것입니다.그러나 무작위로 이 클래스를 삽입하는 것은 권장하지 않습니다.상속은 "관계인가"를 나타냅니다. 예를 들어 개는 동물이고 질감은 이 클래스의 인스턴스입니다.코드에 있는 오브젝트 간의 관계를 실제로 모델링할 수 있는지 자문해 보아야 합니다.논리적 상속 트리는 매우 중요합니다.

  • 추가 클래스가 유형 계층에 논리적으로 맞지 않으면 집계를 사용할 수 있습니다.즉, 이 클래스 유형의 인스턴스 변수를 사이다, 텍스처, 레이어 등의 공통 슈퍼 클래스에 추가합니다.그런 다음 모든 서브클래스에서 getter/setter를 사용하여 변수에 액세스할 수 있습니다.이 모델은 "관계 있음"입니다.

  • 클래스를 인터페이스로 변환할 수도 있습니다.그런 다음 인터페이스를 모든 클래스로 확장할 수 있지만 각 클래스에서 메서드를 올바르게 구현해야 합니다.즉, 코드의 용장성이 어느 정도 존재하지만, 이 경우 그다지 많지 않습니다.

어떤 방식이 가장 마음에 드는지 스스로 결정해야 합니다.개인적으로는 클래스를 인터페이스로 변환할 것을 권장합니다.

힌트 하나:Typescript는 getters와 setters를 위한 통사당인 특성을 제공합니다.http://blogs.microsoft.co.il/gilf/2013/01/22/creating-properties-in-typescript/ 를 참조해 주세요.

새로운 부모 클래스에 함수를 하나씩 추가함으로써 상속할 클래스를 루프하는 것이 매우 해답입니다.

class ChildA {
    public static x = 5
}

class ChildB {
    public static y = 6
}

class Parent {}

for (const property in ChildA) {
    Parent[property] = ChildA[property]
}
for (const property in ChildB) {
    Parent[property] = ChildB[property]
}


Parent.x
// 5
Parent.y
// 6

의 모든 속성ChildA그리고.ChildB에서 액세스 할 수 있게 되었습니다.Parentclass, 단, 인식되지 않습니다.즉, 다음과 같은 경고를 받게 됩니다.Property 'x' does not exist on 'typeof Parent'

설계 패턴에는 "상속보다 구성을 선호한다"는 원칙이 있다.클래스 A에서 클래스 B를 상속하는 대신 클래스 A의 inside 클래스B 인스턴스를 속성으로 배치하면 클래스 A의 inside 클래스B 기능을 사용할 수 있습니다.를 여기와 여기서 볼 수 있습니다.

나의 경우, 나는 연결 상속을 사용했다.이 방법이 도움이 될 것입니다.

class Sprite {
  x: number;
  y: number;

  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
}

class Plane extends Sprite {
  fly(): string {
    return 'I can Fly!'
  }
}

class Enemy {
  isEnemy = true;
}

class Player {
  isPlayer = true;
}

// You can create factory functions to create new instances
const enemyPlane = Object.assign(new Plane(1, 1), new Enemy());
const playerPlane = Object.assign(new Plane(2, 2), new Player());

또한 JS 상속에 관한 Eric Elliott의 기사를 읽을 것을 권장합니다.

  1. 시제품 OO의 심장과 영혼: 연결 상속
  2. 3가지 다른 종류의 프로토타입 상속

여기에는 이미 좋은 답변이 많이 있습니다만, 확장 중인 클래스에 추가 기능을 추가할 수 있는 예를 보여드리고 싶습니다.

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

class Class1 {
    doWork() {
        console.log('Working');
    }
}

class Class2 {
    sleep() {
        console.log('Sleeping');
    }
}

class FatClass implements Class1, Class2 {
    doWork: () => void = () => { };
    sleep: () => void = () => { };


    x: number = 23;
    private _z: number = 80;

    get z(): number {
        return this._z;
    }

    set z(newZ) {
        this._z = newZ;
    }

    saySomething(y: string) {
        console.log(`Just saying ${y}...`);
    }
}
applyMixins(FatClass, [Class1, Class2]);


let fatClass = new FatClass();

fatClass.doWork();
fatClass.saySomething("nothing");
console.log(fatClass.x);

동적 상속 또는 클래스 팩토리를 호출할 수 있습니다.

type ClassConstructor<T> = {
  new (...args: any[]): T;
};

interface IA {
  a: string;
}

interface IB {
  b: string;
}

interface IAB extends IA, IB {}

class EmptyClass {}

function GetA<T>(t: ClassConstructor<T> = EmptyClass as any) {
  class A extends (t as any) implements IA {
    a = 'Default value a';
  }
  return A as unknown as ClassConstructor<IA & T>;
}

function GetB<T>(t: ClassConstructor<T> = EmptyClass as any) {
  class B extends (t as any) implements IB {
    b = 'Default value b';
  }
  return B as unknown as ClassConstructor<IB & T>;
}


class C extends GetA<IB>(GetB()) implements IAB {}

방법을 찾았습니다.

export interface IsA {
    aWork(): void
}

export interface IsB {
   
}

export class A implements IsA {
    aWork() {   }
}

export class B implements IsB {
    bWork() {   }
}

export interface IsAB extends A, B {}
export class IsAB {}

그럼 넌 할 수 있어

export class C extends IsAB {}

또는 심지어

const c = new IsAB {}

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

반응형