2015-11-12 3 views
2

J'ai une superclasse abstraite avec une usine qui renvoie une instance d'une sous-classe. Est-il possible d'avoir une méthode qui est implémentée uniquement dans la superclasse? Dans le code suivant, par exemple, serait-il possible d'enlever Wind :: act()?Comment accéder à l'implémentation de superclasse abstraite lorsqu'elle contient une méthode usine?

abstract class Element { 
    final String action; // what it does 
    String act() => action; // do it 

    factory Element() { 
    return new Wind(); 
    } 
} 

class Wind implements Element { 
    final action = "blows"; 
    act() => action; // Why is this necessary? 
} 

void main() { 
    print(new Element().act()); 
} 

Lors de la suppression de Wind :: act(), une erreur est manquante. En outre, lors de l'extension plutôt que de l'implémentation de la superclasse, l'exclusion de l'implémentation de la sous-classe ne provoque pas d'erreur. Mais avec une méthode d'usine, l'extension n'est pas une option.

+0

Je suppose que ce que je demande est de savoir s'il existe un moyen, lors de l'utilisation d'une fabrique dans une super-classe, d'éviter d'avoir à implémenter toutes les méthodes dans chaque sous-classe. Ce serait mauvais, me semble-t-il. –

Répondre

3

Pour hériter des fonctionnalités de Element à Wind, vous devez soit étendre ou mélanger dans Element dans Wind. Simplement implémenter une interface n'héritera d'aucune implémentation. Par conséquent, vous devez disposer de class Wind extends Element { ... }. Ce n'est actuellement pas possible car Element n'a pas de constructeur génératif que Wind peut utiliser comme super-constructeur. Donc, vous devez ajouter cela aussi, et assurez-vous d'initialiser le champ action dans ce constructeur.

class Element { 
    final String action; 
    Element._(this.action); // Generative constructor that Wind can use. 
    factory Element() = Wind; // Factory constructor creating a Wind. 
    String act() => action; 
} 
class Wind extends Element { 
    Wind() : super._("blows"); 
} 

Le constructeur générative n'a pas besoin d'être privé, mais si vous déclarez et en utilisant toutes les classes seulement à l'intérieur de votre propre bibliothèque, il pourrait aussi bien être.

Une autre option consiste à avoir une classe distincte ElementBase contenant le champ action et la fonction act et un constructeur génératif nommé vide. Les mixins ne sont pas un bon choix dans ce cas, car il n'y a pas de bonne façon de faire action final lorsque les mixins ne peuvent pas avoir de constructeurs.

abstract class Element { 
    String get action; 
    factory Element() = Wind; 
    String act(); 
} 
class ElementBase implements Element { 
    final String action; 
    ElementBase(this.action); 
    String act() => action; 
} 
class Wind extends ElementBase { 
    Wind() : super("blow"); 
} 

Il est un problème commun à la fois un constructeur veulent générative pour les sous-classes et un constructeur d'usine générer l'implémentation par défaut dans une interface/classe squelette. Les interfaces List et Map ont ce problème et l'ont résolu en exposant ListBase et MapBase. Je pense que c'est la meilleure solution lorsque vous exposer la superclasse à d'autres utilisateurs dans d'autres bibliothèques. Si vous ne l'utilisez qu'en interne, j'utiliserai le constructeur génératif private/non-default-named dans la super-classe.

+0

Merci pour la très bonne réponse à la question que j'ai posée mais aussi pour d'autres choses que je me suis demandé, comme comment l'équipe Dart exporte ces interfaces. Je pense que je préfère la 2ème version car l'interface peut être cachée, et peut être réduite à une seule déclaration d'usine. Peut-être pourrait-on parler simplement d'une usine abstraite? Ou peut-être un proxy d'usine? BTW, c'est une sorte d'une déclaration d'attribution étrange avec "Element()" sur la gauche. Des remarques? En outre, lorsque vous utilisez le formulaire plus long ("return new Wind()"), vous pouvez alors paramétrer Element() et Wind(). –

+0

Le paramétrage de l'usine permet bien sûr de déterminer la sous-classe qui est instanciée et de transmettre les paramètres à son constructeur. Très kewl :-) –