( singleton bridge )
Hallo !
Unter Perl gibt es ja die Moeglichkeit auf Funktoinen in einem Modul mittels <PAKETNAME>::<Fumktionsname> zuzugreifen. Wenn man das Paket aber objektorientiert nutzen will, ist das ja nicht ganz unproblmatisch, da es sein koennte dass der Konstruktor noch gar nicht gerufen wurde.
Das kann wie hier gezeigt mittels einer Praeambel
sub tmpdir {
BEGIN Praeambel
my $self = shift;
$self = __PACKAGE__->instance
unless ref $self eq __PACKAGE__;
END Praeambel
#...
}
im Funktionskoerper abgefangen werden, aber es laesst sich vielleicht auch semantisch unterdruecken* :
Hab mal ein Singleton entworfen das das Problem loesen soll:
modules/Log.pm
use strict;
package Log::LogImpl;
if ( defined __PACKAGE__ and __PACKAGE__ eq 'Log' )
{
sub log {
my $class = shift;
my $msg = shift;
print scalar(localtime(time)) . " " . "$msg\n";
}
}
package Log;
my $_self = undef;
BEGIN
{
eben nicht hier konstruiert !
}
my %attrs = ( foo => 'bar'
);
returns singleton reference
sub _getInstance {
$_self ||= do {
# Dies vermeidet einen Aufruf
# wie Log::log
@Log::ISA = 'Log::LogImpl';
bless { %attrs }, 'Log';
};
}
END
{
}
1;
EOF Log.pm
Wenn jetzt ein Client versucht die Methode mittels "Log::log" aufzurufen, wuerde das nicht klappen :
#! /usr/bin/perl -w -I ./modules
LogClient.pl
tests encapsulation cherence
use strict;
use Log;
my $log = Log::_getInstance()
or die 'Could not get instance for log' . "\n" ;
eval ("Log::log('Logged in class scope...')")
and die '...by accident ! Terminating' . "\n"
or print 'Method "log" not in class scope...' . "\n";
$log->log('Logged correctly')
and print '...but in object scope, as intended !' . "\n" ;
EOF LogClient.pl
Das Ganze ist eigentlich ein degeneriertes Brueckenmuster; degeneriert, da hier eben grade nicht die Implementierung aggregiert sondern inkludiert wird, was dem Konzept loser Koppelung, das die "GoF" thematisiert, wiederspricht.
Ausserdem handelt es sich um keine Implemetierungs-"Klasse" (kein bless) sondern um ein einfaches Paket.
Trotzdem find ich das recht praktisch.
Habe noch nicht soviel Erfahrung mit Perl - hier einige Fragen an Euch Wizards:
Ist das Eurer Meinung nach
- eval('undef'); # ;-)
- (void*) NULL; // Denn Perl ist nun mal kein C++
- Voelliger Mist
- Verwirrend fuer den Nutzer
- Kalter Kaffee # "Das mach ich doch seit Beginn der Epoche besser..."
- vielleicht doch irgendwie brauchbar
- ...
?
Ueber Feedback wuerde ich mich sehr freuen
Danke fuer's Lesen
Gruss && schones Wochenende
Holger
*) Ich weiss dass meine Loesung einen Compiler-Fehler provoziert, die Praeambel-Loesung nicht. Genau damit will ich aber eine Aufrufkonverntion erzwingen.