Zurück   Flashforum > Flash > ActionScript > Softwarearchitektur und Entwurfsmuster

Antwort
 
LinkBack Themen-Optionen Ansicht
Alt 11-01-2010, 14:07   #1 (permalink)
thinkin aBout tha lib.
 
Benutzerbild von kaneda
 
Registriert seit: Nov 2001
Ort: Kölle
Beiträge: 1.379
Classmatching

Hallo Leute, ich glaube ich hab endlich mal ein Thema das dieses Forums hier würdig ist

Folgendes: Ich stehe vor einem klassischen Problem und möchte dieses so effizient wie möglich in AS3 lösen: Ich möchte es ermöglichen das verschiedene "Funktionen" bei instanzen verschiedener Klassentypen angewandt werden.

Code:
    getFunctionForInstance(instance: Object):Function

An einem Beispiel angewandt:

Code:
    // MyClass // MyClassB extends MyClass implements MyInterface // MyClassA extends MyClass implements MyInterface // MyClassC implements MyInterface setFunctionForType( MyClass, fnc1 ); setFunctionForType( MyInterface, fnc2 ); setFunctionForType( MyClassA, fnc3 ); getFunctionForInstance( new MyClass() ); // fnc1 getFunctionForInstance( new MyClassA() ); // fnc3 ... da in der Definitionsreihe MyClass nach MyInterface definiert wurde und MyClassA auf beide hin matcht getFunctionForInstance( new MyClassB() ); // fnc2

das ist schonmal ganz schöne Kopfnuss überhaupt zu lösen. Nur frage ich mich dabei noch wie schafft man das halbwegs performant?!

hat jemand ne Idee?

grüsse
Martin.
__________________
Back to community with http://leichtgewicht.at
kaneda ist offline   Mit Zitat antworten
Alt 11-01-2010, 15:27   #2 (permalink)
mushroom powered
 
Benutzerbild von b.asile
 
Registriert seit: Jun 2005
Ort: Amsterdam
Beiträge: 2.647
Willst du vielleicht sowas machen:

http://en.wikipedia.org/wiki/Strategy_pattern

?

PHP-Code:
//invoked from application.initialize
private function init() : void
{
    var 
context:Context;
 
    
context = new Context( new ConcreteStrategyA() );
    
context.execute();
 
    
context = new Context( new ConcreteStrategyB() );
    
context.execute();
 
    
context = new Context( new ConcreteStrategyC() );
    
context.execute();
}
 
package org.wikipedia.patterns.strategy
{
    public interface 
IStrategy
    
{
    function 
execute() : void ;
    }
}
 
package org.wikipedia.patterns.strategy
{
    public final class 
ConcreteStrategyA implements IStrategy
    
{
    public function 
execute():void
    
{
         
trace"ConcreteStrategyA.execute(); invoked" );
    }
    }
}
 
package org.wikipedia.patterns.strategy
{
    public final class 
ConcreteStrategyB implements IStrategy
    
{
    public function 
execute():void
    
{
         
trace"ConcreteStrategyB.execute(); invoked" );
    }
    }
}
 
package org.wikipedia.patterns.strategy
{
    public final class 
ConcreteStrategyC implements IStrategy
    
{
    public function 
execute():void
    
{
         
trace"ConcreteStrategyC.execute(); invoked" );
    }
    }
}
 
package org.wikipedia.patterns.strategy
{
   public class 
Context
   
{
    private var 
strategy:IStrategy;
 
    public function 
Context(strategy:IStrategy)
    {
         
this.strategy strategy;
    }
 
    public function 
execute() : void
    
{  
             
strategy.execute();
    }
    }

Blicke gerade ueberhaupt nicht was du vorhast?
__________________
[ WHEN THE GOING GETS WEIRD THE WEIRD TURN PRO ]

devboy.org

Geändert von b.asile (11-01-2010 um 15:28 Uhr)
b.asile ist offline   Mit Zitat antworten
Alt 11-01-2010, 17:53   #3 (permalink)
Perverted Hermit
 
Benutzerbild von Omega Psi
 
Registriert seit: Mar 2004
Ort: Bremen
Beiträge: 13.419
Eine Referenz zu einer Funktion zu übergeben ist schon die perfomanteste Methode (addEventListener). Das möchte man aber ungern, da es nicht typesafe ist.

Was du möchtest, musst du entscheiden.
Omega Psi ist offline   Mit Zitat antworten
Alt 11-01-2010, 19:07   #4 (permalink)
thinkin aBout tha lib.
 
Benutzerbild von kaneda
 
Registriert seit: Nov 2001
Ort: Kölle
Beiträge: 1.379
Strategy pattern geht aber ...

Naja: Ein Problem beim Strategy Pattern ist das ein Match nicht "höher gewertet" wird als ein anderer. Ich möchte also nicht alle ausführen sondern nur die, die am besten passt, basierend auf der Klasse. In natürlicher Sprache ausgedrückt:

Ich habe eine Waschanlage für alle Fahrzeuge, eine die besonders gut für Flugobjekte funktioniert:
Code:
    setWashingPlantForType( Vehicle, new VehicleWashingPlant() ); setWashingPlantForType( Object, new GeneralWashingPlant() ); setWashingPlantForType( IFlyingVehicle, new FlyingVehicleWashingPlant() ); getWashingPlantForInstance( new Car() ); // VehicleWashingPlant getWashingPlantForInstance( new Airplane() ); // FlyingVehicleWashingPlant

Das heisst also: Es gibt für ein "Flugzeug" drei "Strategies" gibt die ausführbar wären. Car implementiert Object, aber weil Car die Subklasse von Vehicle ist wird Object niedriger gereiht. (Hierarchien bei Interfaces sind auch nicht ausser acht zu lassen!) Das Flugzeug passt zu allen dreien, theoretisch sind "VehicleWashingPlant" und "FlyingVehicleWashingPlant()" sogar gleichwertig. Durch die Reihung kommt das letztere aber raus.

Eine Implementierung die ich mir vorstelle geht ungefähr so vor:
  1. Klasse für Objekt identifizieren
  2. Klassenbaum sortieren
  3. Waschstrasse so lange überprüfen bis ein Match auftritt
  4. Match ausführen.

Code:
    function getWashingPlantForInstance( instance: Object ) {   var className: String = getQualifiedClassName( instance );   var result: IWashingPlant = _washingPlants[className];   if( !result )   {     var hierarchy: ClassHierarchy = _hierarchy[className];     if( !hierarchy )     {       hierarchy = _hierarchy[className] = new ClassHierarchy(describeType(getDefinitionByName(className) ) )     }     for( var i: int = 0; i<hierarchy.levels.length && !result; ++i )     {        var level: Array = hierarchy.levels[i]; // sorted and order by priority - list of types        for( var j: int = 0; j<level.length && !result; ++j )        {           _result = _registeredPlant[ level[j] ];        }     }     _washingPlants[className] = result;   }   return result; }

Das Problem ist das pro Instanz eine ziehmlich Performancezehrende Geschichte ist. Ausserdem wird bei jedem Mal:
Code:
    setWashingPlantForType
der ganze Baum wieder invalid.

Ich kann das jetzt noch viel weiter Spinnen aber vielleicht habt ihr ja ne gute Idee die ich noch nicht hatte. Unabhängig davon das ich noch keine Idee habe wie ich die Klassenhierarchy sauber aufsplitten sollte...

grüsse
Martin.
__________________
Back to community with http://leichtgewicht.at
kaneda ist offline   Mit Zitat antworten
Alt 11-01-2010, 19:10   #5 (permalink)
Neuer User
 
Benutzerbild von the binary
 
Registriert seit: Jul 2001
Ort: Berlin | Friedrichshain
Beiträge: 3.565
[OT]

der kaneda..
immer gut fuer'n knoten im hirn..

[/OT]
__________________
8bm | join ff@BOINC
formpackage.org | audiohunter.de | problematica.de | 8ball-media.de/blog | taikonauten.cn
the binary ist offline   Mit Zitat antworten
Alt 11-01-2010, 19:51   #6 (permalink)
Perverted Hermit
 
Benutzerbild von Omega Psi
 
Registriert seit: Mar 2004
Ort: Bremen
Beiträge: 13.419
Ich sehe das Problem nicht. Wenn du das zu waschende Objekt kennst, kennst du auch die optimale Waschanlage. Die kannst du über eine genestete Fabrik erzeugen:
Code:
    package {   public class WashingPlantFactory   {     public static function create(vehicle:IVehicle):IWashingPlant     {       var washingPlant:IWashingPlant;       if (vehicle is ICar)         washingPlant = CarWashingPlant.create():       else if (vehicle is IPlane)         washingPlant = PlaneWashingPlant.create():       else         throw new ArgumentError("Unknown vehicle");       return washingPlant;     }   } }
Du kannst das auch via "Enum" lösen... oder was auch immer. Aber die Fabriken sollten ein guter Kompromiss sein. Zumal du irgendwo ein Mapping abbilden musst, und das geht mit den Fabriken ganz gut.
Omega Psi ist offline   Mit Zitat antworten
Alt 11-01-2010, 20:56   #7 (permalink)
thinkin aBout tha lib.
 
Benutzerbild von kaneda
 
Registriert seit: Nov 2001
Ort: Kölle
Beiträge: 1.379
Naja

Also diese "if" Abfrage in deinem Beispiel hat ja schon einige Nachteile:
Fix konfiguriert
(mein grösstes Problem hier)
Wenn ich so eine Konfiguration aufbaue (Welche Factories gibts für welche Typen) dann ist die fix und erzeugt potentiell Probleme beim arbeiten mit .swc's und nachladen von Konfiguration. Das mag in manchen Fällen vernachlässigbar sein... aber dennoch.

Konfiguration ist in Methodenkörper
Wenn man mit .swcs arbeitet ist der Methodenkörper von Methoden echt doof herausfindbar. Ohne .swcs sind sie nur gut versteckt und man darf sie suchen.

Performance wird kleiner bei mehr Typen
Jede Instanz wird hier pro Typ überprüft, je komplexer die Konfiguration wird (je länger der Methodenkörper ist) desto höher ist die Wahrscheinlichkeit das es mehrere Abfragen benötigt. Natürlich lässt sich dieses Ergebnis auch irgendwie Cachen.

FYI: Mit Cache ist es ca. 5x langsamer als bei einer einzigen if Abfrage: (Sprich: Ab 5 if Abfragen pro Objekt ist der Cache schneller!)

Mehr Code
Es ist mehr code, von dem die Leute auch wissen müssen wie schreiben. Es ist nicht immer trivial herausfinden welches Interface/welche Klasse jetzt höher bewertet werden soll/wurde.


Aber um der ganzen Geschichte jetzt noch ein bischen Schmackes zu geben, kann ich ja das Problem in seiner ganzen Komplexität enthüllen.

Ich möchte das Ding irgendwie eigentlich verschachteln:

Code:
    var context: Context = new Context();context.setWashingPlantForType( Object, new NormalWashingPlant() );context.setWashingPlantForType( Toyota, new ToyotaWashingPlant() );var childContext: Context = new Context();childContext.setWashingPlantForType( Object, new SpecialWashingPlant() );context.addChild( childContext );var childContext2: Context = new Context();context.addChild( childContext2 );childContext.getWashingPlant( new Car() ); // SpecialWashingPlantchildContext2.getWashingPlant( new Car() ); // NormalWashingPlantchildContext.getWashingPlant( new Toyota() ); // ToyotaWashingPlant
__________________
Back to community with http://leichtgewicht.at
kaneda ist offline   Mit Zitat antworten
Alt 11-01-2010, 22:34   #8 (permalink)
Perverted Hermit
 
Benutzerbild von Omega Psi
 
Registriert seit: Mar 2004
Ort: Bremen
Beiträge: 13.419
Ok, dann verstehe ich richtig: du kennst nicht die Anzahl der Fahrzeuge nicht und auch nicht die Anzahl der Waschanlagen? Ausserdem sollen Fahrzeuge und Waschanlagen nachladbar sein?

Dann brauchst du eine Form von I.o.C. Ich würde dir Spring ActionScript empfehlen. Über den ApplicationContext kannst du dann einfach das Mapping + Priorisierung managen sowie natürlich Injezierung der Instanzen und des Mappings in die Kontexte.

Fertig.
Omega Psi ist offline   Mit Zitat antworten
Alt 11-01-2010, 22:43   #9 (permalink)
Neuer User
 
Benutzerbild von the binary
 
Registriert seit: Jul 2001
Ort: Berlin | Friedrichshain
Beiträge: 3.565
hm...
mein interesse wurde geweckt, aber
leider is die seite grad nich erreichbar..
__________________
8bm | join ff@BOINC
formpackage.org | audiohunter.de | problematica.de | 8ball-media.de/blog | taikonauten.cn
the binary ist offline   Mit Zitat antworten
Alt 11-01-2010, 22:51   #10 (permalink)
Perverted Hermit
 
Benutzerbild von Omega Psi
 
Registriert seit: Mar 2004
Ort: Bremen
Beiträge: 13.419
Spring Actionscript | SpringSource.org
Omega Psi ist offline   Mit Zitat antworten
Alt 11-01-2010, 23:23   #11 (permalink)
thinkin aBout tha lib.
 
Benutzerbild von kaneda
 
Registriert seit: Nov 2001
Ort: Kölle
Beiträge: 1.379
Spring?

Naja, es gibt ja Parsley und anders auch noch als IOC Container. Das hindert mich jetzt aber nicht mich selbst daran zu versuchen, oder? Unabhaengig davon brauche ich eine optimierte Version bei der einzelne Schleifen zählen - ohne irgendwelchen API overhead. Wir sind ja hier in einem Architekturforum, ich denke da waere so eine Frage schon angemessen, also nochmal:

Hat wer ne Idee wie man das am elegantesten/flottesten lösen könnte?
__________________
Back to community with http://leichtgewicht.at
kaneda ist offline   Mit Zitat antworten
Alt 11-01-2010, 23:44   #12 (permalink)
Perverted Hermit
 
Benutzerbild von Omega Psi
 
Registriert seit: Mar 2004
Ort: Bremen
Beiträge: 13.419
Mal eine andere Frage, wieso gibt es verschiedene Waschanlagen für einen Typ Vehicle?
Omega Psi ist offline   Mit Zitat antworten
Alt 12-01-2010, 00:36   #13 (permalink)
thinkin aBout tha lib.
 
Benutzerbild von kaneda
 
Registriert seit: Nov 2001
Ort: Kölle
Beiträge: 1.379
Neugierig?

Ich fands ein schönes neutrales Beispiel; besser als Peka-, Hasel- und Walnussknacker.

Was ich damit machen will ist ein bischen eine Überraschung (auch für mich, bin neugierig)
__________________
Back to community with http://leichtgewicht.at
kaneda ist offline   Mit Zitat antworten
Alt 12-01-2010, 07:25   #14 (permalink)
Perverted Hermit
 
Benutzerbild von Omega Psi
 
Registriert seit: Mar 2004
Ort: Bremen
Beiträge: 13.419
Neugierig, nein.

Ich will meinen Ansatz nur argumentativ untermauern.

Und was die Iterationen, Introspektion etc angeht... das fällt mit I.o.C. weg. Zumal in deiner Version keine Form der Priorisierung möglich ist, jedenfalls keine Explizite.
Omega Psi ist offline   Mit Zitat antworten
Alt 12-01-2010, 10:02   #15 (permalink)
thinkin aBout tha lib.
 
Benutzerbild von kaneda
 
Registriert seit: Nov 2001
Ort: Kölle
Beiträge: 1.379
Hmm

Ich sehe halt bei momentan 4 verschiedene Formen von Wertung die Sinn machen würden:

1) Klassenstruktur (der vererbungsbaum wird beachtet, interfaces bekommen auch einen vererbungsbaum - Ausgangsproblem)
2) Anordnung der Definitionen bei gleichwertigen Klassen
Code:
    setW...(...1); setW...(...2); ...
3) optionaler(!) Hierarchischer Fallback falls nichts gefunden wird.
4) Überschreiben von Childdefinitionen der Hierarchie. Parent kann sagen: Ich weiss das besser als Child. Und festigen der Childdefinition: Child kann sagen, ich ignoriere Parent. (ala CSS)

Wie beurteilen und argumentieren? Naja: Ich würd sagen: Endperformance, Lines of Code, readability.
__________________
Back to community with http://leichtgewicht.at
kaneda ist offline   Mit Zitat antworten
Antwort

Lesezeichen

Themen-Optionen
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks sind an
Pingbacks sind an
Refbacks sind an



Alle Zeitangaben in WEZ +1. Es ist jetzt 18:25 Uhr.

Domains, Webhosting & Vserver von Host Europe
Unterstützt das Flashforum!
Adobe User Group


Copyright ©1999 – 2014 Marc Thiele