hi again,
Entwurfsmuster 1 und 2.
... bevorzugen würdest? Dedlfix und Sven Rautenberg haben mir ja im Verlauf dieses Themas schon gute Begründungen und Erklärungen geliefert, warum insbesondere diese beiden Muster Nachteile mit sich bringen (könnten).
bischen mehr nun, vorhin war die Zeit etwas knapp...Perl und Data Abstraction Layer:
- gut zu machen in Perl ist der Wechsel zwischen byte/character Semantics
- TieKlassen:
tie %bin, 'ORM';
print $bin{'/index.html'}{title}; # byte-Semantics
# setze Character Semantics, title ist in utf8
SvUTF8::utf8(\$bin{'/index.html'}{title});
# jetzt liefern alle Stringfunktionen ein zeichenorientiertes Ergebnis
# length($bin{'/index.html'}{title}); # Anzahl der Zeichen
# substr(), uppercase...
# usw...
Tie-Klassen binden eine Variable an eine Klasse. Zeile 2 erzeugt eine DB-Abfrage, die im Hintergrund abläuft. In der Application wird nur mit Datenstrukturen (z.B. Hash) oder Methoden gearbeitet, der Layer 'ORM' ist austauschbar gegen eine Klasse, welche dieselbe Datenstruktur/Methoden liefert.
Subklassen:
ORM;
ORM::XML;
können alle einer Datei notiert sein. Oder die Subklassen werden in extra Dateien ausgelagert. Perl findet alles ;)
Hotti
PS: etwas vom Thema abschweifend, ein Perl-CGI-Script, objektorientiert geschrieben mit Template und automatisierter Parameterkontrolle. Schön zu sehen ist die Delegeirung der Methoden CGI::param und CGI::header ohne _alle_ Methoden von Klasse CGI zu erben:
#!/usr/bin/perl
# CGI-Script mit Template
###########################################################################
use strict;
use warnings;
use CGI;
my $u = main->new;
# auf Parameter prüfen
if($u->param){
$u->control;
}
print $u->header, $u->out;
exit 0;
###########################################################################
# Parameterkontrolle
# suche anhand der Parameterliste eine passende Funktion
sub control{
my $self = shift;
foreach my $p($self->param){
if(my $code = $self->can($p)){
$self->$code;
return;
}
}
# Wenn keine passende Methode gefunden wurde, unbekannter Parameter
$self->errpush('Unbekannter Parameter', 'Backbutton und erneut versuchen...');
return;
}
# Fehlerspeicher schreiben bei Bedarf
sub errpush{
my $self = shift;
push @{$self->{ERR}}, @_;
}
# Parameter einbauen und Eingaben verarbeiten
# Funktion hat denselben Namen wie der Parameter
sub produkt{
my $self = shift;
# Eingaben erfassen
my $f1 = $self->param('f1');
my $f2 = $self->param('f2');
if($f1 !~ /^\d+$/){
$self->errpush('Bitte nur ganze Zahlen für Wert 1', 'Backbutton und erneut versuchen...');
}
elsif($f2 !~ /^\d+$/){
$self->errpush('Bitte nur ganze Zahlen für Wert 2', 'Backbutton und erneut versuchen...');
}
else{
$self->{TEMPLVAL} = {
f1 => $f1,
f2 => $f2,
produkt => $f1 * $f2,
};
}
}
# Template (Body) ausgeben
# Im Fehlerfall wird eine Fehlerseite ausgegeben
sub out{
my $self = shift;
if(scalar @{$self->{ERR}}){
return sprintf "<p>%s</p>", join "</p><p>", @{$self->{ERR}};
}
else{
$self->{TEMPLVAL}->{action} = $ENV{SCRIPT_NAME};
# Liste mit den Platzhaltern durchgehen
# wenn Werte anliegen, werden die Platzhalter ersetzt
foreach my $s(@{$self->{TEMPLIST}}){
$s = defined $self->{TEMPLVAL}->{$s} ? $self->{TEMPLVAL}->{$s} : '';
}
return sprintf $self->{TEMPLATE}, @{$self->{TEMPLIST}};
}
}
# Konstruktor main-Object
sub new{
my $class = shift;
my $self = bless{
CGI => CGI->new,
TEMPLIST => [],
TEMPLVAL => {},
TEMPLATE => '',
ERR => [],
type => 'text/html',
charset => 'UTF-8',
}, $class;
$self->_template; # Template einbauen
return $self;
}
# Methode erzeugt das Template und legt es ins Objekt
# Das Template ist ein Formular
sub _template{
my $self = shift;
# Definition der Felder/Platzhalter im Template
$self->{TEMPLIST} = ['action', 'f1', 'f2', 'produkt'];
$self->{TEMPLATE} = qq(
<h2>Ein einfaches Formular</h2>
<form action="%s">
<fieldset><legend><strong>Faktor 1, Faktor 2 und Enter:</strong></legend>
<input name="f1" value="%s">
<input name="f2" value="%s">
<input name="produkt" value="Bilde das Produkt" type="submit">
</fieldset>
</form>
<p>Ergebnis: %s</p>
);
}
# Delegierung CGI::param
sub param{
my $self = shift;
return wantarray ? $self->{CGI}->param(@_) : _trim($self->{CGI}->param(@_));
}
# Delegierung CGI::header
sub header{
my $self = shift;
my @args = @_ ? @_ : (-type => $self->{type}, -charset => $self->{charset});
return $self->{CGI}->header(@args);
}
# Entferne Leerzeichen
sub _trim{
my $s = shift or return;
$s =~ s/^\s+//; # leading
$s =~ s/\s+$//; # trailing
return $s;
}