【问题标题】:How to handle events in derived class which are invoked from the base class constructor?如何处理从基类构造函数调用的派生类中的事件?
【发布时间】:2014-01-29 23:45:34
【问题描述】:

我认为这更像是一个设计问题,但这里是这样。

我有一个使用 Typescript 的 Web 应用程序。 我有一个从基类继承的类。 基类在其构造函数中调用一些初始化代码(如下载 .xml 文件)。 下载完成后,它会调用一个事件(例如 Init_Completed)。

现在,我需要派生类来处理这个事件。我知道我可以在基类中注册此事件,并在派生类中重载该处理程序方法。

但是,我需要派生类能够注册此事件处理程序,如下所示:

this.OnLoaded += this.LoadedCompleted;

问题来了:

如何正确设计这个?...因为加载是在 基类构造函数。这意味着加载的事件可能是 在派生类有机会注册/监听之前调用 本次活动。

【问题讨论】:

  • 我建议使用越位 EventEmitter 在一个集中位置处理所有事件。
  • @RobG 这是打字稿
  • 更改基类,以便调用在一个额外的方法中(由构造函数调用)。然后在子类中覆盖该方法。在该重写方法中添加或更改事件处理程序,然后调用基类的方法(super.methodName();)。

标签: typescript event-handling dom-events


【解决方案1】:

您可以在调用基类构造函数之前初始化子类中的成员:

class A{    
    constructor(){
       // register here
    }
}

class B extends A{
    b;
    constructor(){
        this.b = 123;   // Setup members here       
        super();
    }
}

【讨论】:

  • 感谢您的意见。但我认为这并不能解决问题。问题是 B 类注册了一个处理程序(例如:super.OnLoaded.Add(this.MyLoaded); 请注意,此注册过程必须在 super() 之后发生。因为 super() 将最终调用我的 OnLoaded 事件, 类 B 可能会或可能不会及时注册以处理该事件。不能保证类 B 在类 A 调用事件时已准备好。
  • 补充我之前的评论,B 类中的变量 b 实际上在 A 类中(在我的例子中)。所以这不会起作用,因为 A 类(即超级)尚未正式实例化。因此 A.b 是未定义的。
【解决方案2】:

如何正确设计这个?可以在派生类更改注册/侦听此事件之前调用加载的事件。

我建议对只会触发一次的此类事件使用 Promise,例如文件的 load 事件。 Promise 可以很好地处理这个问题

  • 它们支持多个独立的处理程序
  • 注册时间无关紧要 - 当值可用时,每个处理程序都会尽快执行。

您可以choose from many implementations,免费获得简单的错误处理和链接/组合。

【讨论】:

    【解决方案3】:

    我不确定我是否正确理解了您的问题。在我看来你不需要一个活动:

    考虑:

    class Base {
        constructor() {
            init(this.afterInit.bind(this));
        }
    
        init(callback: Function): void {
            //Do something asynchronous
        }
    
        afterInit() {
             //Do something after initialization
        }
    }
    
    class Derived extends Base {
    
         constructor() {
             super();
         } 
    
         afterInit() {
             super.afterInit();
             //Do something else after initialization
        }
    }
    

    但如果它必须使用事件:

    class MyEvent {
    
        register(handler: (sender: any) => void) {
            //Put the handler in a collection
        }
    
        raise() {
            //Invoke all the handlers
        }
    }
    
    class Base {
    
        onAfterInit = new MyEvent();
    
        constructor() {
            init();
        }
    
        init(): void {
            //Do something asynchronous
            //Then invoke the event
            this.onAfterInit.raise();
        }
    }
    
    class Derived extends Base {
    
         constructor() {
             super();
         } 
    
         init() {
             this.onAfterInit.register(sender => {
                 //Do something after initialization
             })
             super.init();
        }
    }
    

    注册处理程序后只需调用 super.init 即可。这有帮助吗?

    【讨论】:

      猜你喜欢
      • 2016-07-19
      • 2018-07-16
      • 2011-05-03
      • 2011-09-27
      • 2018-07-21
      • 2014-03-26
      • 2019-04-19
      • 2015-08-18
      • 1970-01-01
      相关资源
      最近更新 更多