Hallo Sven !
Richtig, und die einzige Chance dagegen ist, dass man das Paket einfach "vernünftig" nutzt.
LOL ! :-)
Dann versuch ich mal eine "Kritik der reinen Vernunft" :
Wenn ich ein Paket schreibe dass ich haeufig wiederverwenden und ggf. auch anderen Programmierern zur Verfuegung stellen werde, moechte ich, dass es moeglichst robust ausgelegt ist und Nebeneffekte moeglichst minimiert.
Wenn die Klasse zwingend mindestens eine Instanz benötigt, und ihre Methoden nicht statisch sinnvoll aufgerufen werden können, ist es in der Verantwortung des Programmierers, das zu tun. Andernfalls muß er mit den Konsequenzen leben.
Beispielsweise:
my $log = Log::_getInstance()
or die 'Could not get instance for log' . "\n" ;
eval ("Log::log('Logged in class scope...')")Wenn die Methode log der Klasse Log statisch aufgerufen wird und das nicht verträgt (weil die Verbindung zu einem offenen Logfile, die durch den Konstruktur hergestellt wird, fehlt), wird sie den Fehler in der Regel
Da moechte ich aus der Regel eine Norm machen.
Sowas:
"Undefined subroutine &Log::log called at LogClient.pl line XY"
finde ich als Hinweis auf einen Fehler recht ausagekraeftig.
Besser als wenn's spaeter an ganz anderer Stelle knallt.
Oder ich sowas auch noch im Clientcode abfangen muss - siehe das 'eval'.
und entsprechende Fehlerwerte zurückgeben. Sollte sie zumindest.
Das gesamte Objekt und alle seine Variablen jeweils auf Konsistenz zu pruefen hielte ich fuer sehr aufwendig und ggf. fehleranfaellig.
Sind ja nicht immer nur Handles, es kann sich ja auch um regulaere Variablen und Attribute handeln. Das ist ja gerade ein der Zusicherungen die andere OO-Sprachen geben; naemlich dass wenn ich auf einer validen Objektreferenz bin, EIN Initialisierer garantiert aufgerufen wurde und der Satz von Variablen existiert.
Vor sowas
(Death*) pMyAssassin = (Death*) NULL;
pMyAssassin->relief(); // ..and get outta here - hopefully HERE !
kann mich auch C++ nicht bewahren.
Aber bei jeder Methode eine Abpruefung zu muessen ob sie auch als Methode gerufen wurde oder nicht fuehrt OO doch ein wenig ad absurdum , oder ?
Um was geht's dir denn konkret? Das Singleton-Pattern kann man auf diverse Arten umsetzen. Man kann sowohl eine separate Klasse zur Instanziierung haben, als auch eine statische getInstance-Methode, oder "nur" eine Funktion mit lokaler statischer Variable...
Aber egal ob Singleton oder normale Instanziierung: Du hast immer das Problem, dass statische Aufrufe, die der Hersteller der Klasse nicht vorgesehen hat, böse sind.
Deshalb lass ich ja auch den "Compiler" ggf. drueber schimpfen.
Gruss
Holger
P.S.: Ein Singleton habe ich deshalb als Beispiel gewaehlt, da man hier die Moeglichkeit hat, die Schnittstelle aus Klassen- und Instanzmethoden zu kombinieren; bei Klassen mit hoeherer Multiplizitaet ist "das" Set von Instanzvariablen ja undefiniert.
Man koennte auf diese Weise einem Singleton-Paket zusaetzlich eine prozedurale Schnittstelle geben und diese geeignet skalieren.
z.B. "log()" waere eine Funktion, bei der man sowas in Betracht ziehen koennte - wenn es noch kein Log gibt, macht sie - transparent - halt eins auf; bei einem "addSink(@)" hingegen moecht eich dass der Nutzer merkt, dass er ein Objekt konfiguriert.
Imo kann ich mit meinem Entwurf genau diese Semantik festlegen.