Singleton als Basisklasse

Objektorientierte Programmiersprache auf Basis einer virtuellen Maschine (https://www.oracle.com/java/)
Antworten
Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Singleton als Basisklasse

Beitrag von Dirty Oerti » Mi Mär 23, 2011 3:52 pm

Tag :)

Also nach allem, was ich bisher gefunden habe, ist das, was ich hier machen möchte, mit Java gar nicht möglich, aber fragen schadet ja nicht :) (Mit C++ wäre es kein Problem ... arg -,- )

Ich habe eine Klasse, die mir verschiedene Funktionen anbietet:

Code: Alles auswählen

public abstract class Escaper {
    private final ArrayList<Character> escapeList;
    // Irgendein lustiger Konstruktor ..
    public final String escape(String txt) {
        // Zugriff auf escapeList
    }
    public final String unescape(String txt) {
        // Zugriff auf escapeList
    }
}
Von dieser Klasse möchte ich dann erben, sprich Klassen haben wie die folgende:

Code: Alles auswählen

public class CSVEscaper extends Escaper {
    //
}
Soweit so gut.


Mein "Escaper" soll allerdings ein Singleton sein. Bzw alle von Escaper abgeleiteten Klassen sollen Singletons sein.

Mein Ziel ist, dass etwas ala folgendem funktioniert:

Code: Alles auswählen

public class CSVEscaper extends Escaper {
    private void setUpSpecialChars() {
        // befüllt nun die (eigene) ArrayList namens escapeList
        this.escapeList.add(';');
    }
}

public class XMLEscaper extends Escaper {
    private void setUpSpecialChars() {
        // befüllt nun die (eigene) ArrayList namens escapeList
        this.escapeList.add('<');
    }
}

// iwo anders:

String escapedText = CSVEscaper.getInstance().escape("Ich bin <ein; boeser Text"); // ergibt: "Ich bin <ein boeser Text"
String escapedText = XMLEscaper.getInstance().escape("Ich bin <ein; boeser Text"); // ergibt: "Ich bin ein; boeser Text"
Wie stelle ich das an?

Prinzipiell müsste "Escaper" ja dann folgendermaßen aussehen:

Code: Alles auswählen

public abstract class Escaper {
    private final ArrayList<Character> escapeList;
    private static final Escaper instance = new Escaper(); //******************

    private Escaper() {
        this.escapeList = new ArrayList<Character>();
        this.setUpSpecialChars();
    }
    public static Escaper getInstance() {
        return Escaper.instance;
    }

    public abstract void setUpSpecialChars();
}
Problem an der markierten Stelle ist:
Escaper ist ja abstract und kann daher nicht instanziiert werden.
Wenn ich Escaper nun nicht mehr abstract deklariere (was ich nicht möchte, denn einen reinen Escaper soll es nicht geben) habe ich das Problem, dass ich damit NUR 1 Singleton Objekt für ALLE von Escaper abgeleiteten Klassen habe.
Sprich:

Code: Alles auswählen

if (CSVEscaper.getInstance() == XMLEscaper.getInstance()) {
    System.out.println("VERDAMMT");
}
else {
    System.out.println("So soll es sein!");
}
Dann dachte ich mir:
Benutz Generics :)

Nächster Versuch:

Code: Alles auswählen


public abstract class Escaper<T extends Escaper> {
    private final ArrayList<Character> escapeList;
    private static final T instance = new T(); //******************

    private Escaper() {
        this.escapeList = new ArrayList<Character>();
        this.setUpSpecialChars();
    }
    public static T getInstance() { //********************
        return T.instance; //**************************
    }

    public abstract void setUpSpecialChars();
}
Tja, das läuft leider nicht. An den markierten Stellen bekomme ich:
non-static type variable T cannot be referenced from a static context
Ich hab nun schon einiges dazu gelesen und noch ein paar andere verrückte Dinge ausprobiert, bin aber bisher auf keinen grünen Zweig gekommen.
Ziel ist wie schon angemerkt spezielle Escaper (für CSV, XML, ...) einfach von Escaper ableiten zu können, die Methode setUpSpecialChars jeweils zu implementieren und sich dann daran zu erfreuen ^^

Ideen? Vorschläge? Hilfe? ^^
Ich hoffe ihr versteht mein Problem bzw, was ich damit bezwecke.

Über Ideen zu einem anderen Design würde ich mich auch freuen?




*edit: Links*
http://c2.com/cgi/wiki?InheritedJavaSingletonProblem
http://en.wikipedia.org/wiki/Generics_in_Java
http://docstore.mik.ua/orelly/java-ent/jnut/ch03_04.htm
http://stackoverflow.com/questions/4285 ... subclasses
http://www.coderanch.com/t/417424/java/ ... ave-public
http://www.coderanch.com/t/458156/java/ ... -executing
http://www.coderanch.com/t/470696/java/ ... eton-Class
http://stackoverflow.com/questions/9164 ... ss-in-java
http://stackoverflow.com/questions/6038 ... d-generics
http://www.angelikalanger.com/GenericsF ... eters.html
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Singleton als Basisklasse

Beitrag von Dirty Oerti » Mi Mär 23, 2011 5:02 pm

Code: Alles auswählen

public abstract class Escaper {
    protected final ArrayList<Character> specialChars;
    
    protected Escaper() {
        this.specialChars = new ArrayList<Character>();
        this.addSpecialChars();
    }
    protected abstract void addSpecialChars();
}

public class CSVEscaper extends Escaper {
    private static final CSVEscaper instance = new CSVEscaper();
    private CSVEscaper() { }
    public static final CSVEscaper getInstance() {
        return CSVEscaper.instance;
    }
    
    protected void addSpecialChars() {
        this.specialChars.add(';');
        this.specialChars.add('\n');
    }
}
So funktioniert es natürlich. Aber nun darf ich die Singleton Geschichte ja in jeder Subklasse erneut schreiben. Klar, das ist nicht aufwändig, aber mir gefällt es nicht.

Ich werd mir mal das angucken:
http://en.wikipedia.org/wiki/Abstract_factory_pattern
Wurde einigen anderen vorgeschlagen, die ebenfalls versucht haben, ein Singleton als Basisklasse zu verwenden.

Eine andere Möglichkeit, die ich nun schon öfters gesehen habe ist die Verwendung einer Hastable in der Basisklasse "Singleton", in der sich dann alle Subklassen eintragen. Das scheint zu funktionieren, aber nur, wenn die Instanzierung der Singletons nicht wie bei mir, direkt beim Laden, sondern erst in der getInstance Methode erfolgt.
Und das ist dann wieder schlecht:
http://www.theserverside.de/singleton-pattern-in-java/
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Singleton als Basisklasse

Beitrag von Xin » Mi Mär 23, 2011 5:57 pm

Dirty Oerti hat geschrieben:Mein "Escaper" soll allerdings ein Singleton sein. Bzw alle von Escaper abgeleiteten Klassen sollen Singletons sein.
Ableitungen beschreiben viele Instanzen mit Gemeinsamkeiten.
Wenn die Gemeinsamkeit ein Singleton (also etwas, von dem es nur eine Instanz gibt) ist, dann hakt's hier.

Wenn ich Dich richtig verstehe, möchtest Du ausdrücken, dass die Basisklasse (Escaper) für jede Ableitung eine statische Variable erstellt, aber selbst gar keine Variable enthält, die für alle Ableitungen gilt. Das Genesys-Schlüsselwort für dieses Konstrukt ist "emit", bzw. hier die Kombination "emit static" denn ich vermisste derartiges auch schon. ^^

Um das Problem zu umgehen, wirst Du vermutlich jeder klasse eine statische Instanz mitgeben, die Du mittels einer abstrakten Funktion/interface abfragen kannst: getEscaper(). Diese Funktion muss jede Ableitung implementieren und kann so eine statische Variable im Namensraum des eigenen Typs zurückliefern.

Soweit richtig verstanden?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Singleton als Basisklasse

Beitrag von Dirty Oerti » Mi Mär 23, 2011 6:45 pm

Xin hat geschrieben:Soweit richtig verstanden?
Wenn ich dich richtig verstanden habe dann ja, du hast mich richtig verstanden :)
Xin hat geschrieben:Ableitungen beschreiben viele Instanzen mit Gemeinsamkeiten.
Wenn die Gemeinsamkeit ein Singleton (also etwas, von dem es nur eine Instanz gibt) ist, dann hakt's hier.
Die Gemeinsamkeit ist nicht "das Singleton", sondern die Eigenschaft der Klasse "ich selbst bin ein Singleton", das ist ein deutlicher Unterschied :)
Xin hat geschrieben:Wenn ich Dich richtig verstehe, möchtest Du ausdrücken, dass die Basisklasse (Escaper) für jede Ableitung eine statische Variable erstellt, aber selbst gar keine Variable enthält, die für alle Ableitungen gilt. Das Genesys-Schlüsselwort für dieses Konstrukt ist "emit", bzw. hier die Kombination "emit static" denn ich vermisste derartiges auch schon. ^^
Exakt. Jede Ableitung braucht eine (eigene) statische Variable/Attribut. Doch das lässt Java wohl nicht mit sich machen (C++ schon ^^ Zwar etwas anders, aber es geht :) )
Xin hat geschrieben:Um das Problem zu umgehen, wirst Du vermutlich jeder klasse eine statische Instanz mitgeben, die Du mittels einer abstrakten Funktion/interface abfragen kannst: getEscaper(). Diese Funktion muss jede Ableitung implementieren und kann so eine statische Variable im Namensraum des eigenen Typs zurückliefern.
Das Problem existiert vermutlich nur noch, weil mich eine Lösung des Problems "Singleton als Basisklasse" interessiert.
Ich hatte meine Klassen heute kurz so, wie in meinem 2 Post oben, sprich jede Ableitung definiert sich selbst als Singleton.
Das gefällt mir aber nicht, deshalb hab ich mir was neues ausgedacht:
Ich lasse den Escaper als einzigstes Singleton, bzw ich gehe einen Schritt weiter und mach den Escaper statisch.
Um die unterschiedlichen Regeln (Escape Regeln, wenn man so will) zu implementieren nehme ich mir ein Interface EscaperRule.

Darin steht, dass jede Klasse, die das implementiert eine Methode

Code: Alles auswählen

public ArrayList<Character> getSpecialChars()
besitzen muss.

Neue Regeln werden eben nun wie folgt gebildet:

Code: Alles auswählen

class CSVRule implements EscaperRule {
    public ArrayList<Character> getSpecialChars() {
        ArrayList<Character> spCh = new ArrayList<Character>();
        spCh.add(';');
        spCh.add('\n');
        return spCh;
    }
}
Das ist an sich auch wieder ärgerlich, da ich nicht mehr als eine Instanz dieser Klasse gebrauchen werde (also, eine würde reichen, mehrere macht keinen Sinn, da sie sich nicht unterscheiden)

Arg.
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Singleton als Basisklasse

Beitrag von Xin » Mi Mär 23, 2011 7:54 pm

Dirty Oerti hat geschrieben:Um die unterschiedlichen Regeln (Escape Regeln, wenn man so will) zu implementieren nehme ich mir ein Interface EscaperRule.

Darin steht, dass jede Klasse, die das implementiert eine Methode

Code: Alles auswählen

public ArrayList<Character> getSpecialChars()
besitzen muss.

Neue Regeln werden eben nun wie folgt gebildet:

Code: Alles auswählen

class CSVRule implements EscaperRule {
    public ArrayList<Character> getSpecialChars() {
        ArrayList<Character> spCh = new ArrayList<Character>();
        spCh.add(';');
        spCh.add('\n');
        return spCh;
    }
}
Das ist an sich auch wieder ärgerlich, da ich nicht mehr als eine Instanz dieser Klasse gebrauchen werde (also, eine würde reichen, mehrere macht keinen Sinn, da sie sich nicht unterscheiden)

Arg.
Das kannst Du doch statisch abbilden!?

Code: Alles auswählen

class CSVRule implements EscaperRule {
    private static ArrayList<Character> specialChars;

    public ArrayList<Character> getSpecialChars() {
        if( specialChars == null )
        {
            specialChars = new ArrayList<Character>();
            specialChars .add(';');
            specialChars .add('\n');
         }
         return specialChars;
    }
}
Das ist genau, was "emit static" abbildet. Die Basisklasse ist abstrakt, aber sie weiß genau, dass eine abgeleitete Klasse die entsprechenden Membervariablen besitzen muss.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Benutzeravatar
Dirty Oerti
Beiträge: 2229
Registriert: Di Jul 08, 2008 5:05 pm
Wohnort: Thurndorf / Würzburg

Re: Singleton als Basisklasse

Beitrag von Dirty Oerti » Mi Mär 23, 2011 10:40 pm

Ja, so wie oben angegeben sieht es dann doch nicht aus. Das ist nun das bisher endgültige Ergebnis:

Code: Alles auswählen

import java.util.ArrayList;

public abstract class EscapeRule {
    public static final EscapeRule DEFAULT = new EscapeRule() {
            protected void setUpSpecialChars() { }
        };

    private final ArrayList<Character> specialChars;


    protected EscapeRule() {
        this.specialChars = new ArrayList<Character>();
        this.specialChars.add(Escaper.ESCAPE);
        this.setUpSpecialChars();
    }
    protected final void addSpecialChar(Character c)
        throws NullPointerException {
        
        if (c == null) {
            throw new NullPointerException(
                "EscapeRule::addSpecialChar(): Param == null");
        }
        else {
            this.specialChars.add(c);
        }
    }
    public final ArrayList<Character> getSpecialChars() {
        return this.specialChars;
    }
    protected abstract void setUpSpecialChars();
}
//##########################################################


public class CSVEscapeRule extends EscapeRule {
    protected void setUpSpecialChars() {
        this.addSpecialChar(';');
        this.addSpecialChar('\n');
    }
}
So dürfte jede von EscapeRule abgeleitete Klasse eine eigene ArrayList haben, auf die sie aber nicht weiter zugreifen kann, sondern nur per addSpecialChar() Character zur ArrayList hinzufügen kann.

Gut oder nicht? ^^
Bei Fragen einfach an daniel[ät]proggen[Punkt]org
Ich helfe gerne! :)
----------
Wenn du ein Licht am Ende des Tunnels siehst, freu dich nicht zu früh! Es könnte ein Zug sein, der auf dich zukommt!
----
It said: "Install Win95 or better ..." So I installed Linux.

Antworten