我相信结合使用接口和基类可以为您工作。它将在编译时强制执行行为要求(rq_ post "below" 指的是上面的帖子,不是这个)。
该接口设置了基类未满足的行为 API。您将无法设置基类方法来调用接口中定义的方法(因为您将无法在基类中实现该接口而无需定义这些行为)。也许有人可以想出一个安全的技巧来允许调用父级中的接口方法。
您必须记住在您将实例化的类中扩展和实现。它满足了对定义运行时失败代码的关注。如果您还没有实现接口(例如,如果您尝试实例化 Animal 类),您甚至无法调用会呕吐的方法。我尝试让接口扩展下面的 BaseAnimal,但它对 Snake 隐藏了 BaseAnimal 的构造函数和“名称”字段。如果我能够做到这一点,那么使用模块和导出可以防止 BaseAnimal 类的意外直接实例化。
将此粘贴到此处以查看它是否适合您:http ://www.typescriptlang.org/Playground/
// The behavioral interface also needs to extend base for substitutability
interface AbstractAnimal extends BaseAnimal {
// encapsulates animal behaviors that must be implemented
makeSound(input : string): string;
}
class BaseAnimal {
constructor(public name) { }
move(meters) {
alert(this.name + " moved " + meters + "m.");
}
}
// If concrete class doesn't extend both, it cannot use super methods.
class Snake extends BaseAnimal implements AbstractAnimal {
constructor(name) { super(name); }
makeSound(input : string): string {
var utterance = "sssss"+input;
alert(utterance);
return utterance;
}
move() {
alert("Slithering...");
super.move(5);
}
}
var longMover = new Snake("windy man");
longMover.makeSound("...am I nothing?");
longMover.move();
var fulture = new BaseAnimal("bob fossil");
// compile error on makeSound() because it is not defined.
// fulture.makeSound("you know, like a...")
fulture.move(1);
我遇到了 FristvanCampen 的答案,如下所示。他说抽象类是一种反模式,并建议使用实现类的注入实例来实例化基本“抽象”类。这是公平的,但也有人提出反对意见。自己阅读:
https ://typescript.codeplex.com/discussions/449920
第 2 部分:我有另一种情况,我想要一个抽象类,但我无法使用上面的解决方案,因为“抽象类”中定义的方法需要引用匹配接口中定义的方法。所以,我参考了 FristvanCampen 的建议。我有不完整的“抽象”类,带有方法实现。我有未实现方法的接口;这个接口扩展了“抽象”类。然后我有一个扩展第一个并实现第二个的类(它必须扩展两者,因为超级构造函数否则无法访问)。请参阅下面的(不可运行的)示例:
export class OntologyConceptFilter extends FilterWidget.FilterWidget<ConceptGraph.Node, ConceptGraph.Link> implements FilterWidget.IFilterWidget<ConceptGraph.Node, ConceptGraph.Link> {
subMenuTitle = "Ontologies Rendered"; // overload or overshadow?
constructor(
public conceptGraph: ConceptGraph.ConceptGraph,
graphView: PathToRoot.ConceptPathsToRoot,
implementation: FilterWidget.IFilterWidget<ConceptGraph.Node, ConceptGraph.Link>
){
super(graphView);
this.implementation = this;
}
}
和
export class FilterWidget<N extends GraphView.BaseNode, L extends GraphView.BaseLink<GraphView.BaseNode>> {
public implementation: IFilterWidget<N, L>
filterContainer: JQuery;
public subMenuTitle : string; // Given value in children
constructor(
public graphView: GraphView.GraphView<N, L>
){
}
doStuff(node: N){
this.implementation.generateStuff(thing);
}
}
export interface IFilterWidget<N extends GraphView.BaseNode, L extends GraphView.BaseLink<GraphView.BaseNode>> extends FilterWidget<N, L> {
generateStuff(node: N): string;
}