ค้นหาเว็บไซต์

typescript - การเก็บรวบรวมคลาสที่มีการตกแต่ง (โดยไม่รวมคลาสรีจิสตรี)


ฉันมีคลาสตัวจัดการเหตุการณ์ซึ่งควรจะกระตุ้นตัวฟังเมื่อเกิดเหตุการณ์บางอย่าง ฉันต้องการลงทะเบียนตัวฟังเหตุการณ์ผ่านตัวตกแต่ง ซึ่งตอนนี้มันใช้งานได้แล้ว แต่ฉันยังไม่ได้พอใจกับวิธีแก้ปัญหาปัจจุบันของฉัน 100%

ปัจจุบัน ตัวฟังเหตุการณ์จะถูก "เก็บรวบรวม" โดยทะเบียนทั่วโลกและต่อมาจะลงทะเบียนในตัวกระจายเหตุการณ์ ในโค้ด ตัวตกแต่งของฉัน (แบบง่าย) ดูเหมือนว่า:

// Decorator
export const EventListener = (events: string[]) => {
  return (target: Type<object>): void => {
    EventListenerRegistry.set(target);
  };
};

// Listener example
@EventListener(['start'])
class OnStart {
  public handle() {
  }
}

ตัวฟัง OnStart จะถูกเรียกใช้งานทันทีที่เหตุการณ์ start ถูกส่งออก

สิ่งที่ฉันไม่ชอบเกี่ยวกับแนวทางนี้คือความจำเป็นของ EventListenerRegistry ซึ่งมีลักษณะดังนี้:

export const EventListenerRegistry = (new class {
    protected listeners = [];

    public set(target) {
        this.listeners.push(target);
    }
});

การนำเข้า EventListenerRegistry หมายถึงการนำเข้าตัวอย่างเดียวกันในทุกจุด ทำให้มันค่อนข้างเหมือน "singleton"

ผู้ฟังของฉันถูก require ผ่าน glob ดังนั้นวิธีนี้ทำให้สามารถลงทะเบียนผู้ฟังของฉันกับตัวส่งเหตุการณ์โดยอัตโนมัติโดยไม่ต้องทำงานเพิ่มเติมใด ๆ

แต่จะมีความเป็นไปได้อื่นนอกจากการใช้คลาสรีจิสทรี (ขี้เหร่) ไหม?

คำตอบ #1

ฉันจะใช้คอนเทนเนอร์ IoC หนึ่งตัว ตัวที่ดีสำหรับ TypeScript คือ Inversify ซึ่งจะช่วยให้สิ่งต่าง ๆ เป็นไปแบบนี้:

import { injectable, inject } from 'inversify';

enum EventType {
  Start,
}

interface IEvent {
  type: Event;
  handle(): void;
}

@injectable()
class OnStart implements IEvent {
  public readonly type = EventType.Start;
  public handle() {
  }
}

@injectable()
class Application {
  public constructor(@multiInject(EVENT) public events: IEvent[]) {
  }
}

แต่นี่หมายความว่าคุณต้องทำการมัดเอง:

export const EVENT = symbol('event');
container.bind<IEvent>(EVENT).to(OnStart);
...

อย่างไรก็ตาม ถ้าคุณต้องการให้เหตุการณ์ลงทะเบียนตัวเองโดยอัตโนมัติจริง ๆ ผมเดาว่าคุณสามารถแค่ import container เข้าไปใน decorators ของคุณแล้วทำการ binding ที่นั่นได้

บทความที่เกี่ยวข้อง