Halihallo Struppi
Natürlich könntest du dies auch über AUTOLOAD erreichen, aber das
ändert nichts am Sachverhalt (ist eben auch eine Methode und somit
in der Symboltabelle definiert, welche eben auf Packetebene
arbeitet). Oder du müsstest leider einfach alle benötigten Variablen
als Methoden exportieren, ob sie nun existieren oder nicht...Das ist genauso wie ich es bisher mache und es funktioniert auch einwandfrei, aber AUTLOAD ist extrem langsam.
Ich glaube, dass dir die Lösung über AUTOLOAD einfach nicht so gut
gefällt :-) und ich verstehe das (AUTOLOAD ist böse :-)).
Oder aber, du musst für jeden Objekttyp eine eigene Klasse schreiben,
was ja normalerweise auch die richtige und bei vielen
Programmiersprachen die einzige Vorgehensweise ist.Wahrscheinlich hast du recht. Ich fand es nur extrem lästig, dass ich für jedes (Daten)Objekt alles nochmal schreiben muss.
Mir kommt da grad ein guter Satz in den Sinn:
<cite>
Wo kein Bedürfnis ist, kann man eines schaffen
</cite>
Mit anderen Worten: Wenn es zu lästig ist, für jeden Datentyp (z.B.
Tabelle in einer Datenbank) ein eigenes Modul anzufertigen, dann
musst du dir einfach die Vorteile einreden und dich des Resultats
ergötzen :-)
Wäre z.B. folgendes nicht sehr schön (zwar aufwendig, aber schön):?
Terminkalenderanwendung (Mehrere Benutzer haben mehrere Termine).
Table termin
term_id
user_id
term_begin_date
term_end_date
term_alert_date
term_expiry_date
term_warn_once
und
Table user
user_id
user_name
user_family_name
user_email
Dann folgende drei Klassen:
Klasse User.pm (extends DataAbstraction.pm)
new( user_id )
create( %user_properties )
delete()
#inherited getData(@fields)
#inherited setData(%props)
addTermin(%props)
selectTermin(%conditions)
deleteTermin(%conditions)
copyAllEntriesToUser( user_obj )
Klasse Termin.pm (extends DataAbstraction.pm)
new( user_obj, term_id )
create( user_obj, %termin_properties )
delete()
#inherited getData(@fields)
#inherited setData(%props)
getUser()
copyToOtherUser( user_obj )
moveToOtherUser( user_obj )
und zum Schluss:
Klasse DataAbstraction.pm
new( table, primary_key )
create(%props)
delete()
setData(%props)
getData(@fields)
-------
DataAbstraction.pm übernimmt die ganze Datenhaltung, erstellt, löscht
und liest/schreibt alle Daten aus der Datenbank. "Darübergestülpt"
sind alle spezifischen Datentypen, wie z.B. Termin und User. Diese
haben nun fixe Felder und diese können bereits zur Compile-Time ganz
am Anfang festgelegt werden.
Was ich vorher mit "wo kein Bedüfnis ist, kann man sich eines
schaffen" meinte ist, dass jetzt nicht nur auf die Daten über
Class::Accessor zugegriffen werden kann, sondern auch die ganze
Funktionalität (neuer User zufügen, neuen Termin anhängen, Termine
selektieren etc.) in diesen spezifischen Datentypklassen abgelegt
ist. _Das_ halte ich für sehr ästhetisch und dann nehme ich auch
gerne den Mehraufwand in Kauf, für alle Datentypen (User, Termin)
die Felder explizit anzugeben und für jeden Datentypen eine Klasse
anzulegen.
Na, keine Ahnung, vielleicht kannst du dich genauso gut selber
täuschen wie ich mich. Vielleicht lässt sich dies jedoch auch nicht
auf deine Aufgabenstellung anwenden... Egal :-)
Also hatte ich mir überlegt (und wie gesagt auch mit AUTLOAD umgesetzt) ich schreib ein Objekt was einerseits alle Datenfelder als Methoden zu Verfügung stellt, das hat den Vorteil, dass ich nicht versuche auf Felder zuzugreifen, die nicht existieren und ich habe die Möglichkeit diese im Bedarfsfalle mit eigenen Methoden zu überschreiben. Zusätzlich habe ich jeweils eine Funktion eingebaut die mir die Daten als HASH zurückgibt und eine die die geänderten Felder zurückgibt, so dass ich z.b. beim schreiben in die Datenbank nur die geänderten Felder speichern kann.
Naja, also entweder du verfolgst etwas ähnliches wie ich oben
beschrieben habe, oder du verwendest AUTOLOAD (oder beides zusammen,
dann liessen sich alle Felder über DataAbstraction.pm auslesen und
ggf. über die Datentypklassen (Termin/User) erweitern). Das sind für
mich die einzigen (guten) Möglichkeiten, die ich sehe.
Mein Ziel mit Class::Accessor war halt das langsame AUTLOAD zu vermeiden und ich hatte die wage Hoffnung, dass es irgendwie gehen muss die Methode, die Class::Accessor benutzt evtl. dafür zu benutzen aber bisher waren alle meine Versuche gescheitert, da ich dieses Foo in der Zeile "Foo->mk_accessors($new, @$fields);" nicht so hingebogen bekomme, dass es ein zur Laufzeit entstandenes Objekt beinhaltet.
Ich versuche es nochmals:
Class::Accessor - auch wenn es nicht so aussieht - arbeitet immer
auf Klassen-/Packetebene, das hat perlinterne Gründe und diese kannst
du nicht einfach so in den Wind schlagen; da Class::Accessor mit der
Methoden in der Symboltabelle arbeitet und damit im Kontext
des Packetes arbeitet und nicht im Kontext einer Instanz einer
Klasse (Objekt).
Es gibt nur eine Möglichkeit, eine Methode im "Objekt-Kontext" zu
definieren und diese wird dich wohl kaum glücklich machen...:
$a = new Whatever;
$a->{field} = 15;
$a->{_field} = sub {
return $a->{field};
};
und dann:
print $a->{_field}->();
$a->{_field}->() ist nun eine Methode, die nur und wirklich nur in
dieser *einen* Instanz von Whatever existiert (naja, es ist keine
Methode mehr, aber das, was einer "Instanz-Methode" bei Perl am
nächsten kommt).
Hm, schade wa? - Finde ich eigentlich auch... Obwohl, naja, es ist
sauberer so wie es ist. Instanzmethoden gibt es nicht und somit auch
die Möglichkeit nicht, in Perl $a->field variabel zu gestalten (es
sei denn mit den bereits genannten "Tricks" [AUTOLOAD])
Viele Grüsse
Philipp