Dynamisch Klassen überladen?
Chrisi
- perl
Hi zusammen,
vermutlich eine grundsätzliche Frage die zu den Basics gehört, stellen muss ich Sie aber trotzdem :-)
Ich habe ein paar Klassen mit den Namen "controller, common, driver". Die Klasse controller ist mein Hauptobjekt mit dem ich auch arbeite, common enthält nur Globale Funktionen wie z.B. trim,round etc. die mir in der controller Klasse helfen. Die Klasse driver enthält spezielle Mehoden die ich gern dynamisch in die Klasse controller (ueber)laden will. Alle Driver haben immer die gleichen Methoden, die ich dann durch den Controller anspreche.
Mein Problem ist es das driver Modul dynamisch in das controller Modul zu laden.
Ein Beispiel:
package controller;
use strict;
use warnings;
use common; # soll immer im controller und auch in allen
# und moeglichst auch in den unterklassen vorhanden sein
our @ISA = qw( common );
sub new {
my ($class,$driver) = @_;
my $self = {};
## nun will ich das driver modul
## laden und alle methoden und variablen vom driver
## in den controller holen
## weil es versch. driver gibt muss dieses modul dynamisch
## geladen werden - allerdings nie mehr als 1 driver
use $driver;
our @ISA = $driver;
bless $self,$class;
return $self;
}
und hier ein Driver:
package mydriver;
use strict;
use warnings;
sub new {
my ($class) = @_;
my $self = {'a' => 1,'b' => 2};
bless $self,$class;
return $self;
}
sub a {
}
sub b {
}
Kann mir jemand sagen wie man den driver ordentlich in den controller laden kann?
Danke für eure Hilfe & Viele Grüße
Chrisi
use common; # soll immer im controller und auch in allen
# und moeglichst auch in den unterklassen vorhanden sein
our @ISA = qw( common );
Ich würde hier entweder use base qw(common) oder use parent qw(common) verwenden.
use $driver;
Das geht nicht, i.d.R. bietet sich hier soetwas an
eval "use $driver;";
die $@ if $@;
our @ISA = $driver;
und dann push @ISA, $driver;
Kann mir jemand sagen wie man den driver ordentlich in den controller laden kann?
z.b. so:
#!/usr/bin/perl -w
use strict;
package controller;
sub new {
my ($class,$driver) = @_;
my $self = {};
bless $self,$class;
eval "use $driver;";
die $@ if $@;
push @controller::ISA, $driver;
return $self;
}
package main;
my $c = controller->new('myTest');
use Data::Dumper;
print Dumper $c;
$c->a;
myTest.pm:
package myTest;
sub func_a {
print 'Hallo!', __PACKAGE__, "\n";
}
1;
Struppi.
Hi Struppi,
danke für deine Antwort!
eval "use $driver;";
die $@ if $@;
push @controller::ISA, $driver;
Das habe ich verstanden und soeben eingebracht.
Meine "our @ISA" Versuche habe ich gegen "use base qw(..." getauscht, das sieht deutlich ordentlicher aus :-)
Viele Grüße
Chrisi
PS.: Habe mir gerade deine HP angeschaut, der Rubber für die Fotos ist eine Coole Sache.
Meine "our @ISA" Versuche habe ich gegen "use base qw(..." getauscht, das sieht deutlich ordentlicher aus :-)
Ich hatte das parent Modul ja schon erwähnt, hier eine kurze Übersicht warum es besser als base ist: http://datenzoo.de/pub/gpw2008/Probleme-mit-base.pm/probleme-mit-base.pm-talk.html
PS.: Habe mir gerade deine HP angeschaut, der Rubber für die Fotos ist eine Coole Sache.
Jaja, Javascript ist toll ;-)
Struppi.
Hi Struppi,
danke für die Info.
Mir ist gerade beim überladen noch etwas aufgefallen was ich nicht ganz verstehe.
Alle Variablen die ich im controller habe werden automatisch an den driver vererbt, aber was passiert mit den Variablen die ich im driver gesetzt habe? Oder besser gesagt, wie kann ich dort Variablen setzen die ich innerhalb des drivers nutzen kann?
Ich würde jetzt einfach auf Konstanten setzen, aber bevor ich mich da in was verlaufe frage ich lieber noch einmal nach :-)
Hast du da einen Tipp für mich?
Viele Grüße, Chrisi
Moin Moin!
Mir ist gerade beim überladen noch etwas aufgefallen was ich nicht ganz verstehe.
Alle Variablen die ich im controller habe werden automatisch an den driver vererbt,
Nö, höchtens Attribute und Methoden werden vererbt. Wenn Variablen "vererbt" werden, hast Du ein fürchterliches Monster mit Export & Co. gebaut.
aber was passiert mit den Variablen die ich im driver gesetzt habe? Oder besser gesagt, wie kann ich dort Variablen setzen die ich innerhalb des drivers nutzen kann?
Bringst Du jetzt Klasse und Instanz durcheinander?
Alexander
Hi Alexander,
Bringst Du jetzt Klasse und Instanz durcheinander?
Ich denke da liegt mein Problem. Ich habe mir gerade deinen Beitrag zum nachladen angesehen und bin dabei auf deine import Methode gestossen.
Das bringt mich auf eine Idee, ich verpasse meinem driver einfach eine Methode mit dem Namen import:
sub import {
return my $variables = {keya=>1,keyb=2}
}
Und nach dem Laden von driver hole ich mir per import() meine Variablen in den Controller:
my $drivervars = $driver->import();
Bin ich da auf dem richtigen Weg?
Viele Grüße, Chrisi
Moin Moin!
Bin ich da auf dem richtigen Weg?
Völlig daneben. Ich habe so langsam das Gefühl, Du kennst OOP nur vom Buzzword Bingo.
import() ist für Perl reserviert, und eigentlich nur dazu da, Funktionen(!) in andere Namespaces zu exportieren, typischerweise durch den IMPLIZITEN import()-Aufruf innerhalb von use.
Bei OOP solltest DU nahezu keine Variablen benötigen, außer um Objekt-Instanzen zu speichern. Typischerweise packst Du alles, was Du ohne OOP in einer Variablen ablegen würdest, in Objekt- oder Klassenattribute.
Alexander
Moin Moin!
»» use $driver;
Das geht nicht, i.d.R. bietet sich hier soetwas an
eval "use $driver;";
die $@ if $@;
Och nö, zum nachladen von Modulen muß man doch nicht nochmal den Parser bemühen!
~~~perl
{
(my $fn="$driver.pm")=~s|::|/|g;
require $fn;
# und ggf: $driver->import(...); für Module mit Exporten.
}
Alexander
(my $fn="$driver.pm")=~s|::|/|g;
Das schmeckt ja grauenhaft. Ich kann mindestens drei Fälle nennen, in denen das nicht mal funktioniert wie beabsichtigt.
Am besten benutzt man: http://p3rl.org/Module::Load
Moin Moin!
»» (my $fn="$driver.pm")=~s|::|/|g;
Nochmal um Irritationen zu vermeiden: Die Aufgabe ist, ein OOP-Modul zur Laufzeit zu laden. Wir reden explizit nicht über Pragmas oder Non-OOP-Module, die massiv mit dem Exporter arbeiten.
Das schmeckt ja grauenhaft. Ich kann mindestens drei Fälle nennen, in denen das nicht mal funktioniert wie beabsichtigt.
Die wären?
Betriebssysteme, die den Slash nicht als Pfad-Trenner akzeptieren? Win32 und OS/2 AKZEPTIEREN den Slash, wie schon alle DOS-Versionen seit 2.0. Alle Unix-Derivate inklusive Linux, BSD und MacOSX (und cygwin) nutzen den Slash als Pfad-Trenner. MacOS bis einschließlich 9 wird Probleme haben, das ist richtig, aber tot.
Alexander
Ich lese deine konkrete Aufgabenstellung und erkenne abstrakt: dies ist Polymorphismus, aber du willst gar keine Vererbung, hier geht es um Roles. Beschreibung des Konzepts: http://my.safaribooksonline.com/059600737X/perl6ess2-CHP-6-SECT-3
Warum keine Vererbung? Der theoretische Grundlage wird entbehrt: es gibt nämlich keine »is-a«-Verbindung zwischen den Klassen, sondern »does-a«.
Gleichwohl Struppi schon eine Lösung auf Basis von Vererbung lieferte: wenn dir korrektes Klassendesign am Herzen liegt, spiele ein wenig mit Roles herum. Die Implementation in Pugs und Rakudo ist vollständig, für Perl5 gibt es die Module Moose::Role bzw. Mouse::Role (wie immer erhältlich auf CPAN).
Live-Hilfe, gerne zu konzeptionellen und auch dämlichen Fragen, gibt es auf irc.perl.org im Kanal #moose (englisch).