Uważam, że użycie kombinacji interfejsów i klas podstawowych może być dla Ciebie przydatne. Będzie wymuszać wymagania behawioralne w czasie kompilacji (rq_ post „below” odnosi się do powyższego postu, który nie jest tym).
Interfejs ustawia behawioralny interfejs API, który nie jest spełniony przez klasę podstawową. Nie będziesz mógł ustawić metod klasy bazowej do wywoływania metod zdefiniowanych w interfejsie (ponieważ nie będziesz w stanie zaimplementować tego interfejsu w klasie bazowej bez konieczności definiowania tych zachowań). Może ktoś może wymyślić sejf wymyśli sztuczkę, która pozwoli na wywołanie metod interfejsu w rodzicu.
Musisz pamiętać o rozszerzeniu i wdrożeniu w klasie, którą utworzysz. Zaspokaja obawy związane ze zdefiniowaniem kodu błędu wykonania. Nie będziesz nawet w stanie wywoływać metod, które mogłyby rzygać, jeśli nie zaimplementujesz interfejsu (na przykład, jeśli spróbujesz utworzyć instancję klasy Animal). Próbowałem, aby interfejs rozszerzył BaseAnimal poniżej, ale ukrył konstruktor i pole „name” BaseAnimal przed Snake. Gdybym był w stanie to zrobić, użycie modułu i eksportu mogłoby zapobiec przypadkowemu bezpośredniemu utworzeniu klasy BaseAnimal.
Wklej tutaj, aby zobaczyć, czy to działa dla Ciebie: 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);
Natrafiłem na odpowiedź FristvanCampen, o której mowa poniżej. Mówi, że klasy abstrakcyjne są anty-wzorcem i sugeruje, że jedna podstawowa klasa „abstrakcyjna” korzysta z wstrzykniętej instancji klasy implementującej. To jest sprawiedliwe, ale wysunięto kontrargumenty. Przeczytaj sam:
https://typescript.codeplex.com/discussions/449920
Część 2: Miałem inny przypadek, w którym chciałem klasy abstrakcyjnej, ale nie mogłem użyć powyższego rozwiązania, ponieważ zdefiniowane metody w „klasie abstrakcyjnej” musiały odnosić się do metod zdefiniowanych w dopasowanym interfejsie. Tak więc, w pewnym sensie korzystam z porad FristvanCampen. Mam niepełną klasę „abstrakcyjną” z implementacjami metod. Mam interfejs z niezaimplementowanymi metodami; interfejs ten rozszerza klasę „abstrakcyjną”. Następnie mam klasę, która rozszerza pierwszą i implementuje drugą (musi rozszerzyć obie, ponieważ w przeciwnym razie superkonstruktor jest niedostępny). Zobacz (niedziałającą) próbkę poniżej:
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;
}
}
i
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;
}