【问题标题】:Instantiate class with abstract method用抽象方法实例化类
【发布时间】:2019-02-11 07:55:39
【问题描述】:

使用 Java,我们可以创建具有抽象方法的 ActionListener 类的实例,如下所示(已经有一段时间了):

new ActionListener(){
  @Override
  public void actionPerformed(ActionEvent e) {
     // whatever
  }
}

使用 TypeScript,这是我能做到的最接近的:

export abstract class ActionListener {

  constructor(f: any) {
    this.actionPerformed = f;
  }

  abstract actionPerformed(input: string): string;

}


new ActionListener(input => {

});

至少有2个问题:

  1. 如果您在 TS 中使用抽象方法,则该类必须抽象(我认为在 Java 中您可以拥有可以稍后实现的抽象方法)。

  2. 我不知道如何将输入函数 f 的类型与解析方法的类型联系起来。

有谁知道是否有办法用 TS 做到这一点?

也许我们不能将abstract 与 TS 一起使用,而必须更像这样:

type ActionPerformed = (input: string) => string;

export class ActionListener {

  parse: ActionPerformed;

  constructor(f: ActionPerformed) {
    this.parse = f;
  }

}

new ActionListener(input => {
  return 'foo';
});

【问题讨论】:

    标签: typescript tsc typescript3.0


    【解决方案1】:

    使用 Java,我们可以创建具有抽象方法的 ActionListener 类的实例

    不,您不能创建具有抽象方法的类的实例。调用该抽象方法时应该发生什么?

    可以做的是你可以创建一个实现该抽象方法的抽象类的子类,你可以创建一个该子类的实例。这正是您的 Java 代码正在做的事情。您的 Java 代码没有实例化 ActionListener 的对象。您的 Java 代码正在创建 ActionListener子类,它会覆盖 actionPerformed 并实例化 该子类

    现在,TypeScript 当然支持子类化,所以你可以在 TypeScript 中做完全相同的事情:创建一个子类,覆盖/实现方法,然后实例化 那个子类

    new (class extends ActionListener { 
        actionPerformed(input: string): string {
            return "Hello"
        }
    })(input => {
        // Whatever
    });
    

    或者你可以这样做:

    new (class implements ActionListener {
      actionPerformed(input: string): string {
        return "Hello"
      }
    });
    

    Playground here.

    【讨论】:

    • “不,您不能创建具有抽象方法的类的实例。调用该抽象方法时应该发生什么?”你可以在 Java 中做到这一点。我不确定你的问题是什么意思。每个实例都创建自己的抽象方法实现。
    • 我觉得class implements ActionListener 更有意义,不知道
    • 在您发布的代码中,您创建了一个实现actionPerformedActionListener 的子类。 ActionListener 的这个子类不是抽象的,它没有抽象方法。然后,实例化这个子类。在您发布的代码中,您从不实例化具有抽象方法的类。您实例化一个 该类的子类,它有 no 抽象方法。如果您知道使用抽象方法(不使用反射或字节码操作)实例化类的方法,请随时分享;我不知道。
    • 在 java 中,代码中的每个此类调用都将创建一个新的匿名内部类,该内部类扩展抽象类,因此抽象类不会被实例化,但匿名类实例将是可见的。以这种方式实现的接口也是如此。
    • 我使用implements 方式添加了一个编辑,我认为这也很好,但不确定
    【解决方案2】:

    这在 JavaScript 或 TypeScript 中不是必需的。 Java 没有将函数作为第一类对象的概念,lambda 只是实现函数接口的实例化对象的糖。

    因此,JS/TS 中的惯用方式是这里没有类,而是简单地传递一个回调函数:

    interface ActionListener {
      (ev: Event) => void;
    }
    
    function iNeedAnActionHandler(actionListener: ActionListener) {
      // do stuff
      const ev = new Event(); // whatever
      actionListener(ev);
    }
    

    不需要笨拙的类和接口实现来传递回调。

    【讨论】:

      猜你喜欢
      • 2015-10-06
      • 2021-01-08
      • 2015-08-04
      • 1970-01-01
      • 2017-02-05
      • 1970-01-01
      • 2012-09-08
      相关资源
      最近更新 更多