Einfache Entwurfsmuster sind oft schwer zu verstehen
Viele mir bekannte Praktiker, ich gehöre auch dazu, halten nicht viel von Entwurfsmustern. Praxisnah programmieren heißt zweckmäßig programmieren und den Anwender interessiert ein etwaiges zugrunde liegendes Entwurfmuster herzlich wenig. Hier jedoch gehts um ein paar interessante Sachen und Hintergründe zum klassenübergreifenden Datenaustausch aus der Sicht der Programmierer.
Oft werden im eigenen Code
Instanzen fremder Klassen (nicht mit der eigenen Klasse verwandte Klassen) benötigt. In der Praxis unterscheide ich zunächst, wann das passiert, also, ob das von Anfang an feststeht oder ob es sich erst zur Laufzeit ergibt. Darüber hinaus wäre noch zu unterscheiden, ob fremde Klassen hard coded
oder per externe Konfiguration einzubinden sind. In meinem Framework gibt es alle möglichen Varianten und so stellt sich auch die Frage, inwieweit sowas wartungsfreundlich ist oder auch nicht. Lassen wir dazu einfach ein paar Beispiele sprechen.
Die eigene Klasse sei die package main
, erstellen wir eine Instanz der eigenen Klasse:
use CGI; my $main = bless{ CGI => CGI->new() }, 'main'; # oder im Konstruktor sub new{ my $class = shift; return bless{ CGI => CGI->new() }, $class; } # oder als Übergabe my $cgi = CGI->new(); sub new{ my $class = shift; my $cgi = shift; return bless{ CGI => $cgi }, $class; }
Das Attribut CGI
ist eine Instanz der nicht verwandten Klasse CGI
. Anstatt alle Methoden von der Klasse CGI
zu erben, delegieren
wir nur eine Methode:
sub param{ my $self = shift; return $self->{CGI}->param(@_); }
Und das ist auch der eigentliche Grund dafür, das CGI
-Modul von Beginn an einzubinden: Die Methode param()
wird auf jeden Fall benötigt. Die Delegation erlaubt es, die Methode param()
als eine eigene Methode aufzurufen.
So richtig Sinn macht das nur, wenn die namentlich gewünschte Methode in eine externe (und dedizierte) Datei ausgelagert wird. Das könnte dann zum Beispiel so aussehen:
# Datei param.pm use CGI; *param = sub{ my $self = shift; $self->{CGI} = CGI->new() unless exists $self->{CGI}; return $self->{CGI}->param(@_); }; __END__
Beim ersten Aufruf der Methode param()
an einer beliebigen Stelle im eigenen Code wird obenstehende Datei param.pm
per AUTOLOAD
eingebunden, d.h., deren Code wird kompiliert. Die Instanz der Klasse CGI
wird als Attribut der eigenen Klasse erstellt, dies aber auch nur beim ersten Aufruf der Methode param()
. Danach kann die param()
-Methode beliebig oft aufgerufen werden.
Aufgrund einer solchen Vorgehensweise wird die fremde Klasse vollständig von der eigenen Klasse abstrahiert. Das heißt dass die Instanz der eigenen Klasse den Namen der fremden Klasse überhaupt nicht kennen muss und letztendlich ist die fremde Klasse austauschbar. Diese Herangehensweise ist auch bekannt unter der Bezeichnung Factory Method.
Charakteristisch für mein Framework ist die Bindung eines URL
an eine Subklasse
. Der Name der Subklasse ist einerseits also von außen konfigurierbar und steht andererseits auch erst dann fest, nachdem der Request entgegengenommen wurde.
Design Patterns sind was für Theoretiker. In der Praxis gibt es fließende Übergänge, so dass es wenig sinnvoll bzw. zielführend ist, nach einem bestimmten Entwurfsmuster entwickeln zu wollen. Gründe dafür, bestimmte Dinge nicht zu tun, gibt es da schon eher. Instanzen fremder Klassen dem eigenen Konstruktor zu übergeben, führt sehr schnell zu einem unübersichtlichen Code der auch schwer zu warten ist. Besser ist es, solche Instanzen entweder im eigenen Konstruktor zu erzeugen oder im Rahmen einer Factory.
Vorheriger Artikel: Just another OOP Tutorial for Perl
Nächster Artikel: Aggregation und Delegation sinnvoll nutzen für Objektübergreifenden Datenaustausch
Datenschutzerklärung: Diese Seite dient rein privaten Zwecken. Auf den für diese Domäne installierten Seiten werden grundsätzlich keine personenbezogenen Daten erhoben. Das Loggen der Zugriffe mit Ihrer Remote Adresse erfolgt beim Provider soweit das technisch erforderlich ist. sos@rolfrost.de.