2010-10-14 6 views
4

Possible en double:
How to have Moose return a child class instance instead of its own class, for polymorphismDans Moose, comment faire pour que le constructeur d'une classe renvoie une instance d'une sous-classe?

Supposons que j'ai deux classes associées MyClass :: A et B MaClasse :: qui sont les deux sous-classes de MyClass. Je voudrais que le constructeur de MyClass prenne un nom de fichier, lise le fichier et, selon le contenu du fichier, décide si le fichier est de type A ou B. Ensuite, il devrait construire un objet de la sous-classe appropriée et le retourner . Editer: En fait, il devrait appeler le constructeur de la sous-classe appropriée et retourner le résultat.

Ainsi, par exemple, après ce code,

my $filename = "file_of_type_A.txt"; 
my $object = MyClass->new($filename); 

$object devrait être une instance de MyClass :: A. Cela semble un comportement valide, car $object->isa('MyClass') retournera toujours vrai. Je pensais à utiliser l'introspection pour obtenir une liste de toutes les sous-classes de MyClass, puis j'essayais de les construire à tour de rôle, jusqu'à ce que l'une réussisse. Cependant, je ne vois pas de moyen de modifier le constructeur Moose pour le faire. Ni les BUILDARGS ni les hooks BUILD ne semblent appropriés.

Alors, comment puis-je modifier le constructeur d'une classe Moose pour sélectionner une sous-classe appropriée et déléguer la construction à cette sous-classe?

+4

Je tapais une réponse et a soudainement eu un sentiment de déjà vu, se rendant compte que [cela est arrivé avant dans une question précédente] (http://stackoverflow.com/questions/2994072/how-to- has-moose-return-a-child-class-instance-au lieu de-sa-propre-classe-pour-pol). À savoir: vous devez appeler une méthode d'usine, qui décidera du constructeur de la classe à appeler. – Ether

+0

Oui, c'est un doublon très bien. Votez pour fermer. –

+1

Eh bien, maintenant je comprends enfin à quoi sert une usine. –

Répondre

5

Comme l'a dit Ether ci-dessus, vous devriez avoir une méthode d'usine pour effectuer cette tâche. J'aime mettre la méthode factory dans un paquet/une classe séparée à partir des choses qu'elle produit Habituellement, il s'agit d'une classe virtuelle qui n'a aucun attribut ou constructeur, mais si vous voulez faire des choses comme garder une trace de ce que vous avez fait, vous pouvez créer un objet d'usine réel.

package MyFile::Factory; 

sub make_file_object { 
    my $class = shift; 
    my $filepath = shift; 

    my $type = $class->determine_file_type($filepath); 
    my $file_class = $class->get_class_for_file_type($type); 

    return $file_class->new($filepath, @_); 
} 

# implement those other methods down here. 

1; 
+0

Puis-je utiliser l'usine comme ça? 'mon $ object = MyFile :: Factory-> make_file_object ($ filepath)' –

+0

Aussi, la super-classe commune devrait-elle devenir un rôle à la place? La seule raison pour laquelle je voulais que ce soit une classe en premier lieu était de lui donner un constructeur, et si j'utilise une usine à la place, alors ce n'est pas nécessaire. –

+0

Votre classe de fabrique ne fait pas partie de la hiérarchie d'héritage MyFile. Il s'assoit à côté et agit sur la hiérarchie. – daotoad

Questions connexes