236 votes

Déclarer une méthode d'abstact dans TypeScript

J'essaie de comprendre comment définir correctement les méthodes abstraites dans TypeScript:

En utilisant l'exemple d'héritage d'origine:

 class Animal {
    constructor(public name) { }
    makeSound(input : string) : string;
    move(meters) {
        alert(this.name + " moved " + meters + "m.");
    }
}

class Snake extends Animal {
    constructor(name) { super(name); }
    makeSound(input : string) : string {
        return "sssss"+input;
    }
    move() {
        alert("Slithering...");
        super.move(5);
    }
}
 

Je voudrais savoir comment définir correctement la méthode makeSound, de sorte qu'elle soit typée et possible de trop en user.

De plus, je ne suis pas sûr de savoir comment définir correctement les méthodes protected - cela semble être un mot clé, mais n'a aucun effet et le code ne sera pas compilé.

360voto

Steve Fenton Points 55265

Tapuscrit seulement eu public ou private modificateurs - protected n'est pas disponible encore (il est prévu pour les v1 un peu de temps).

Les classes abstraites peuvent être ajoutés à l'avenir de la Machine - il est un élément de travail ouvert pour que. Cependant, le dernier commentaire attaché à l'élément de travail, de cette écriture (2013-09-04), dit:

Il n'existe pas de plans pour tout type de classe abstraite syntaxe

Dans l'intervalle, le compilateur nécessite un corps de la fonction pour être déclaré. Vous pouvez vous assurer que la proposition de la méthode abstraite n'est pas exigible:

class Animal {
    constructor(public name) { }
    makeSound(input : string) : string {
        throw new Error('This method is abstract');
    }
    move(meters) {
        alert(this.name + " moved " + meters + "m.");
    }
}

class Snake extends Animal {
    constructor(name) { super(name); }
    makeSound(input : string) : string {
        return "sssss"+input;
    }
    move() {
        alert("Slithering...");
        super.move(5);
    }
}

Selon la façon dont les classes abstraites sont mis en œuvre à la Machine (et en supposant qu'ils seront), il est possible que la syntaxe que vous avez utilisé ne sera valable.

25voto

Tiddo Points 1249

Si vous prenez Erics réponse un peu plus loin, vous pouvez en fait créer un assez décent de mise en œuvre de classes abstraites, avec le plein appui pour le polymorphisme et la possibilité d'appeler mis en œuvre des méthodes de la classe de base. Commençons avec le code:

/**
 * The interface defines all abstract methods and extends the concrete base class
 */
interface IAnimal extends Animal {
    speak() : void;
}

/**
 * The abstract base class only defines concrete methods & properties.
 */
class Animal {

    private _impl : IAnimal;

    public name : string;

    /**
     * Here comes the clever part: by letting the constructor take an 
     * implementation of IAnimal as argument Animal cannot be instantiated
     * without a valid implementation of the abstract methods.
     */
    constructor(impl : IAnimal, name : string) {
        this.name = name;
        this._impl = impl;

        // The `impl` object can be used to delegate functionality to the
        // implementation class.
        console.log(this.name + " is born!");
        this._impl.speak();
    }
}

class Dog extends Animal implements IAnimal {
    constructor(name : string) {
        // The child class simply passes itself to Animal
        super(this, name);
    }

    public speak() {
        console.log("bark");
    }
}

var dog = new Dog("Bob");
dog.speak(); //logs "bark"
console.log(dog instanceof Dog); //true
console.log(dog instanceof Animal); //true
console.log(dog.name); //"Bob"

Depuis l' Animal classe nécessite une mise en œuvre de l' IAnimal il est impossible de construire un objet de type Animal sans avoir un valide la mise en œuvre des méthodes abstraites. Notez que pour le polymorphisme de travail vous avez besoin pour passer autour des instances de IAnimal, pas Animal. E. g.:

//This works
function letTheIAnimalSpeak(animal: IAnimal) {
    console.log(animal.name + " says:");
    animal.speak();
}
//This doesn't ("The property 'speak' does not exist on value of type 'Animal')
function letTheAnimalSpeak(animal: Animal) {
    console.log(animal.name + " says:");
    animal.speak();
}

La principale différence ici avec Erics réponse est que le "résumé" de la classe de base nécessite une implémentation de l'interface, et donc ne peut pas être instancié sur son propre.

4voto

Eric Points 120

Je crois que l'utilisation d'une combinaison d'interfaces et de classes de base pourrait travailler pour vous. Il va appliquer comportementale exigences au moment de la compilation (rq_ post "ci-dessous" fait référence à un post ci-dessus, ce qui n'est pas celui-ci).

L'interface définit le comportement de l'API qui n'est pas rencontré par la classe de base. Vous ne serez pas en mesure de définir des méthodes de classe de base pour appeler sur les méthodes définies dans l'interface (parce que vous ne serez pas en mesure de mettre en œuvre cette interface dans la classe de base, sans avoir à définir ces comportements). Peut-être quelqu'un peut venir avec un coffre-fort astuce pour permettre d'appeler des méthodes d'interface dans le parent.

Vous devez vous rappeler de les étendre et de les mettre en œuvre dans la classe que vous instancier. Il répond à des préoccupations au sujet de la définition à l'exécution code de non. En outre, vous ne même pas être en mesure d'appeler les méthodes de vomir si vous n'avez pas mis en œuvre l'interface (comme si vous essayez d'instancier l'Animal de la classe). J'ai essayé d'avoir l'interface de prolonger la BaseAnimal ci-dessous, mais il se cachait, le constructeur et le champ 'nom' de BaseAnimal de Serpent. Si j'avais été capable de le faire, l'utilisation d'un module et les exportations auraient empêché accidentel direct de l'instanciation de la BaseAnimal classe.

Collez ce ici pour voir si cela fonctionne pour vous: 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);

Je suis tombé sur FristvanCampen la réponse de comme lien ci-dessous. Il dit que les classes abstraites sont un anti-modèle, et suggère que l'on instancie la base de "abstrait" classes à l'aide de l'injection d'une instance de mise en œuvre de la classe. C'est juste, mais il existe des contre arguments. Lisez vous-même: https://typescript.codeplex.com/discussions/449920

Partie 2: J'ai eu un autre cas où je voulais une classe abstraite, mais j'ai été empêché d'utiliser ma solution ci-dessus, parce que les méthodes définies dans la "classe abstraite" nécessaire de se reporter aux méthodes définies dans l'interface correspondant. Donc, je l'outil FristvanCampen les conseils, en quelque sorte. J'ai le incomplète "abstrait" de la classe, avec la méthode mise en œuvre. J'ai l'interface avec les méthodes non implémentées; cette interface s'étend le "résumé" de la classe. J'ai ensuite une classe qui étend la première et met en œuvre la deuxième (il doit s'étendre à la fois parce que le super constructeur est inaccessible autrement). Voir la (non-exécutables) de l'échantillon ci-dessous:

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;
    }
}

et

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;

}

-23voto

rq_ Points 37

Non, non, non! S'il vous plaît ne pas essayer de faire votre propre "abstrait" des classes et des méthodes de la langue ne prend pas en charge cette fonctionnalité; il en va de même pour toutes les langues fonction que vous souhaitez une langue prise en charge. Il n'y a pas de bonne façon de mettre en œuvre des méthodes abstraites en caractères d'imprimerie. La structure de votre code avec les conventions de nommage, de sorte que certaines classes ne sont jamais directement instancié, mais sans explicitement l'application de cette interdiction.

Aussi, l'exemple ci-dessus est uniquement destiné à fournir cette application au moment de l'exécution, et non PAS au moment de la compilation que vous pouvez attendre en Java/C#.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X