Tôi tin rằng việc sử dụng kết hợp các giao diện và các lớp cơ sở có thể phù hợp với bạn. Nó sẽ thực thi các yêu cầu hành vi tại thời gian biên dịch (rq_ post "bên dưới" đề cập đến một bài viết ở trên, không phải là bài này).
Giao diện đặt API hành vi không được đáp ứng bởi lớp cơ sở. Bạn sẽ không thể đặt các phương thức lớp cơ sở để gọi các phương thức được xác định trong giao diện (vì bạn sẽ không thể thực hiện giao diện đó trong lớp cơ sở mà không phải xác định các hành vi đó). Có lẽ ai đó có thể đưa ra một mẹo an toàn để cho phép gọi các phương thức giao diện trong cha mẹ.
Bạn phải nhớ mở rộng và thực hiện trong lớp bạn sẽ khởi tạo. Nó thỏa mãn mối quan tâm về việc xác định mã thời gian chạy thất bại. Bạn thậm chí sẽ không thể gọi các phương thức sẽ gây khó chịu nếu bạn chưa triển khai giao diện (chẳng hạn như nếu bạn cố gắng khởi tạo lớp Animal). Tôi đã thử để giao diện mở rộng BaseAnimal bên dưới, nhưng nó đã ẩn hàm tạo và trường 'tên' của BaseAnimal từ Snake. Nếu tôi đã có thể làm điều đó, việc sử dụng một mô-đun và xuất khẩu có thể ngăn chặn việc khởi tạo trực tiếp ngẫu nhiên của lớp BaseAnimal.
Dán cái này vào đây để xem nó có phù hợp với bạn không: 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);
Tôi đã xem qua câu trả lời của FristvanCampen như được liên kết dưới đây. Ông nói rằng các lớp trừu tượng là một mô hình chống và gợi ý rằng một lớp khởi tạo các lớp 'trừu tượng' bằng cách sử dụng một thể hiện của một lớp triển khai. Điều này là công bằng, nhưng có những lập luận chống lại được thực hiện. Đọc cho chính mình:
https://typescript.codeplex.com/discussions/449920
Phần 2: Tôi đã có một trường hợp khác khi tôi muốn một lớp trừu tượng, nhưng tôi đã bị ngăn không sử dụng giải pháp của mình ở trên, bởi vì các phương thức được định nghĩa trong "lớp trừu tượng" cần để tham khảo các phương thức được định nghĩa trong giao diện phù hợp. Vì vậy, tôi xin lời khuyên của FristvanCampen. Tôi có lớp "trừu tượng" không hoàn chỉnh, với việc triển khai phương thức. Tôi có giao diện với các phương thức chưa thực hiện; giao diện này mở rộng lớp "trừu tượng". Sau đó tôi có một lớp mở rộng lớp thứ nhất và thực hiện lớp thứ hai (nó phải mở rộng cả hai vì siêu xây dựng không thể truy cập bằng cách khác). Xem mẫu (không chạy được) dưới đây:
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;
}
}
và
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;
}