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 ที่นั่นได้
