假设我有一个接口(interface)
interface I <T extends InternalResult> {
doStuff(): T;
}
和实现这个接口(interface)的两个具体类:
class A implements I <InternalAResult> {
doStuff(): InternalAResult {
// implementation
}
}
class B implements I <InternalBResult> {
doStuff(): InternalBResult {
// implementation
}
}
我的客户端不能直接执行 doStuff()
,但需要一个实现 Executer
接口(interface)的类的实例,例如其中一个:
interface Executer <T, R> {
execute(it: T): R;
}
class AExecuter implements Executer <A, AResult> {
execute(it: A): AResult {
let internalResult = it.doStuff();
// ... do something specific with internalResult create result
return result;
}
}
class BExecuter implements Executer <B, BResult> {
execute(it: B): BResult {
let internalResult = it.doStuff();
// ... do something other specific with internalResult create result
return result;
}
}
对于这种情况,我总是使用 Java 中的 Visitor 模式。我可以创建一个访问者,将两个 Executer
实例传递给它并使用 A
和 B
实现 visit
方法> 重载,创建无条件解决方案,如下所示:
class Visitor {
private aExecuter: AExecuter;
private bExecuter: BExecuter;
visit(it: A): Result {
return this.aExecuter.execute(it);
}
visit(it: B): Result {
return this.bExecuter.execute(it);
}
}
现在,TypeScript/JavaScript 中没有方法重载这样的东西。但是,除了创建这样的条件之外,还有什么替代方法呢?:
if (it instanceof A)
aExecuter.execute(it);
else if (it instanceof B)
bExecuter.execute(it);
注意:我想让A
类对AExecuter
一无所知。这会增加这两个类之间的耦合,我无法轻松切换 AExecutor
的实现。
最佳答案
您可以使用 typescript compiler team 的方法使用并有一个区分字段类型的字段,将 instanceof
替换为简单的字符串/数字比较,这可能更便宜(尽管您应该测试您的用例):
enum Types {
A, B
}
interface I <T extends InternalResult> {
readonly type : Types;
doStuff(): T;
}
class A implements I <AResult> {
readonly type = Types.A
doStuff(): AResult {
return new AResult();
}
}
class B implements I <BResult> {
readonly type = Types.B
doStuff(): BResult {
return new BResult();
}
}
class Visitor {
private aExecuter: AExecuter = new AExecuter();
private bExecuter: BExecuter = new BExecuter();
visit(it: A | B): AResult | BResult {
// Since we don't have a default return, we will get a compiler error if we forget a case
switch(it.type){
case Types.A : return this.aExecuter.execute(it); break;
case Types.B : return this.bExecuter.execute(it); break;
}
}
}
另一种需要较少编写(但类型安全性较低)的方法是使用构造函数名称作为访问正确方法的键:
class Visitor {
private aExecuter: AExecuter;
private bExecuter: BExecuter;
visit(it: A | B): AResult | BResult {
let visitor: (it: A | B) => AResult | BResult = (this as any)['visit' + it.constructor.name];
if(visitor == null) {
throw "Visitor not found"
}
return visitor.call(this, it)
}
visitA(it: A): AResult {
return this.aExecuter.execute(it);
}
visitB(it: B): BResult {
return this.bExecuter.execute(it);
}
}
关于javascript - TypeScript 中访问者模式的替代方案(避免 instanceof 条件),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51168935/