solution de Taurayi est source d'inspiration, car il établit que le chaînon manquant explicite de la classe à Symbole, assurer le contenu du symbole est instancié que ce soit la classe de niveau supérieur ou juste une classe de base une chaîne d'héritage. Un effet secondaire de cette approche, cependant, est qu'elle ajoute un niveau de confinement supplémentaire dans le contenu de Card, à savoir le conteneur CardSprite.
J'ai réussi à implémenter une solution générique pratique qui préserve réellement le comportement d'empilement attendu de tous les symboles hérités. Par exemple, si vous cochez "numChildren" sur une instance de Symbol2 ci-dessous, il s'agira exactement de la somme de Symbol1.numChildren et de Symbol2.numChildren, il s'agit donc d'une véritable fusion de contenu de symbole. Lorsque votre symbole est dans une chaîne d'héritage, ajoutez simplement cet appel "ensureLinkage" à tout moment après un appel à la méthode super(). Remarque: N'oubliez pas de vous assurer que le symbole de niveau supérieur définit également explicitement une classe avec le modèle ci-dessus.
Lorsque Symbol2 et Symbol1 sont liés aux symboles correspondants dans la bibliothèque, leur contenu s'empile maintenant. Il suffit de déposer une occurrence de Symbol2 sur la scène et de tester le film. Vous verrez que le contenu de Symbol1 apparaît sous le contenu de Symbol2. (Remarque: n'apparaît pas dans le concepteur, car il s'agit d'un correctif d'exécution).
La mise en œuvre de ensureLinkage est la suivante:
package
{
import flash.utils.getQualifiedClassName;
import flash.utils.getDefinitionByName;
import flash.events.Event;
public class BugFixes
{
public static var linkageMonitor:Object = new Object();
private static var linkageMonitorAuthority:Array = new Array();
public function BugFixes()
{
}
public static function ensureLinkage(instance:*, className:String)
{
if (getQualifiedClassName(instance) != className) //detect non-top-level construction
{
//prevent inevitable factorial-recursive construction
var stack:Array = linkageMonitor[instance] as Array;
if (stack == null)
{
stack = new Array();
stack["numChildren"] = instance.numChildren;
linkageMonitor[instance] = stack;
}
var barredByAuthority:Boolean = false;
if (linkageMonitorAuthority.length > 0)
barredByAuthority = (linkageMonitorAuthority[linkageMonitorAuthority.length - 1] as Array).indexOf(className) > -1;
if (stack.indexOf(className) == -1 && !barredByAuthority)
{
stack.push(className); //remember construction
trace("ensuring Linkage of inherited class " + className);
//perform top-level construction to trigger symbol linkage and child object instantiation
linkageMonitorAuthority.push(stack);
var temp:* = new (getDefinitionByName(className) as Class)();
linkageMonitorAuthority.pop();
//Merge children
while (temp.numChildren > 0)
instance.addChild(temp.getChildAt(0));
//Merge properties
for (var prop:String in temp)
instance[prop] = temp[prop];
}
else
{
trace("skipping redundant construction of: " + className);
}
}
else
{
var stack:Array = linkageMonitor[instance] as Array;
if (stack != null)
{
var nc:int = int(stack["numChildren"]);
trace("construction completing for " + getQualifiedClassName(instance));
for (var i:int = 0; i < nc; i++)
instance.setChildIndex(instance.getChildAt(0), instance.numChildren - 1);
}
delete linkageMonitor[instance]; //top-level constructor is completing, all relevant sub-objects have been constructed
}
}
}
}
Fondamentalement, il détecte si les symboles auront besoin instancié manuellement, en voyant que le nom de classe qualifié de l'instance correspond au nom de la classe attendue passé à la appel de la classe elle-même. Comme il est appelé après "super", les appels commencent à la classe la plus profonde et s'assurent que les enfants de son symbole de bibliothèque sont instanciés en créant une instance temporaire de premier niveau et en revendiquant ses enfants comme siens. Le tout premier appel de l'instance récupère également le nombre initial d'enfants présents, puisque le clip de premier niveau de la pile aura déjà instancié ses enfants avant que le code du constructeur ne soit exécuté. En stockant ce nombre, une dernière étape peut ensuite amener ces premiers enfants au sommet où ils appartiennent. La classe n'assure aucune récursion inutile en utilisant une pile "autorité" pour s'assurer que la pile principale est toujours visible pour les constructeurs enfants. Un problème est que les traits statiques ne sont pas persistants, mais uniquement parce qu'AS3 ne fournit pas d'API pour accéder aux traits (par exemple, une fois que vous dessinez une ligne dans le concepteur ou avec graphics.lineTo, il n'y a aucun moyen d'accéder par programmation ce coup à des fins de dénombrement ou de modification, sauf pour effacer tous les coups à la fois). Ce n'est donc pas une limitation de cette approche, mais plutôt l'API de Flash.
Peut-être que Adobe était tout simplement incapable de trouver cette mise en œuvre: P
S'il vous plaît noter que si vos symboles font un travail qui lie l'instance de symbole autre code, il pourrait y avoir un problème, étant donné que cette classe revendique la propriété des enfants d'une instance temporaire. Il revendique également les valeurs des références de variables de l'instance temporaire en utilisant une boucle for, mais c'est ce qu'il peut faire de mieux dans une implémentation générique comme celle-ci.
"La classe de base de votre card_mc (Card MovieClip) peut être votre classe Card mais elle ne rend pas votre carte Card synonyme de card_mc." Cela cloue le problème sur la tête, mais c'est aussi trompeur, car dans Flash, quand j'instancie "Carte", il * est * synonyme du contenu du symbole qui lui est lié. Par exemple, vous ne pouvez pas avoir deux symboles différents héritant de la même définition de classe, car le joueur assimile la classe au symbole, et ne connaîtrait pas le contenu du symbole à instancier lorsque vous instanciez directement la classe. – Triynko
Votre approche crée ce lien explicite (manquant) de Class à Symbol en ajoutant explicitement une instruction de composition au constructeur, qui est toujours appelée instanciée comme une classe de premier niveau ou comme une classe de base dans une hiérarchie d'héritage. Le problème avec ceci, c'est que c'est encore de la composition manuelle, et comme CardSprite est un symbole séparé, vous ne pouvez pas accéder à ses instances directement sur la classe "Card". Par exemple, plutôt que d'accéder à Card.instance_name, vous devez y accéder en tant que Card.getChildAt (0) .instance_name. – Triynko