繁体   English   中英

如何在 TypeScript 中创建 Java 函数式接口默认方法的模拟?

[英]How to create the analogue of Java functional interface default method in TypeScript?

有一个在 TypeScript/JavaScript ( Script4J ) 中实现 Java(FX) API 的项目。 现在我想修改 Comparator 功能接口。 这是默认解决方案:

export interface Comparator<T> {
    (o1: T, o2: T): number;
}

这种解决方案允许添加比较器作为箭头函数(如 java lambda),例如:

let comparator: Comparator<number> = (n1: number, n2: number): number => {
    return n1 - n2;
};
let treeMap: SortedMap<number, string> = new TreeMap<number, string>(comparator);

如您所见,代码非常干净。 现在我需要添加到 TypeScript Comparator 接口的 next 方法(Java 代码):

default Comparator<T> reversed() {
    return Collections.reverseOrder(this);
}

考虑到我无法更改 API,最好的方法是什么?

打字稿中没有与默认接口方法实现的直接等效项。 您可以使用将默认值分配给比较器函数的 ea 函数:

export interface Comparator<T> {
    (o1: T, o2: T): number;
    reversed() : any // not sure what return type should be, maybe (o1: T, o2: T) => number ?
}

function comparatorWithDefault<T>(fn: (o1: T, o2: T) => number) {
    function reversed(this: Comparator<T>) {
        return Collections.reverseOrder(this);
    }
    return Object.assign(fn, { reversed });
}

let comparator: Comparator<number> = comparatorWithDefault((n1: number, n2: number): number => {
    return n1 - n2;
})
let treeMap: SortedMap<number, string> = new TreeMap<number, string>(comparator);

不像 Java 将成员添加到Comparator会破坏很多现有代码。

经过一番思考,我决定达到最大 Java API 的唯一方法是使用抽象类而不是接口。 这是我的解决方案:

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

type ComparatorFunc<T> = (o1: T, o2: T) => any;

abstract class Comparator<T> {

    public static lambda<T>(func: ComparatorFunc<T>): Comparator<T> {
        return new class extends Comparator<T> {
            public compare(o1: T, o2: T): number {
                return func(o1, o2);
            }
        }
    }

    public abstract compare(o1: T, o2: T): number;
}

//VAR 1 - lambda
let lambdaComparator: Comparator<number> = Comparator.lambda((n1: number, n2: number) => { return n1 - n2;});
console.log("Lambda comparator");
console.log(lambdaComparator.compare(100, 50));

//VAR 2 - full implementation
class MyComparator implements Comparator<number> {

    public compare(o1: number, o2: number): number {
        return o1 - o2;
    }
}
applyMixins (MyComparator, [Comparator]);

let classComparator: MyComparator = new MyComparator();
console.log("Class comparator");
console.log(classComparator.compare(100, 50));

好处:

  • 我们非常接近 Java API。
  • 方法的名称是可见的。
  • 我们可以使用箭头函数来快速创建类的实例。
  • 我们可以创建实现多个接口的类。
  • 由于实现接口的所有类都通过一个函数(applyMixins),我们可以添加对可以检查某个实例是否实现某个接口的方法的支持(通过 instanceof 可以轻松检查类)。

缺点:

  • 每次程序启动/页面打开时,为每个类调用 applyMixins。
  • 当 TypeScript 检查它们的实现时,有必要在每个实现中显示空的默认方法 (reversed:()=> Comparator)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM