Discussion:
static Methoden und Felder und die Ableitung
(zu alt für eine Antwort)
Sascha Raubal
2004-09-14 13:14:16 UTC
Permalink
Hi!

Also, irgendwann treiben mich diese static-Regeln zur Verzweiflung.
Einerseits kann man so herrlich Speicher sparen, wenn eh für alle Instanzen
das gleiche gilt, andererseits hab ich dann Probleme mit Ableitungen.

Folgende Ausgangssituation:

Ich will verschiedene Varianten von Adressen haben, zum Beispiel:

class SimpleAddress
{
String street;
String ZIP;
String city;
Integer type;
}

class BiggerAddress extends SimpleAddress
{
String county;
String country;
}

Das Feld type soll eine Kennung beinhalten, ob es sich z.B. um eine private
oder geschäftliche Adresse handelt.
Damit man das auch mit halbwegs sprechenden Bezeichnern machen kann, hab ich
ein Properties-Objekt benutzt:

class SimpleAddress
{
protected static Properties types = initAddressTypes();
.....
public static Properties initAddressTypes()
{
Properties p = new Properties();
p.put("undefined", new Integer(0));
p.put("home", new Integer(1));
p.put("work", new Integer(2));
return p;
}

public Properties getAddressTypes()
{
return types.clone();
}

}

Hielt mich ja für sooo schlau, das mit 'ner Methode zu initialisieren, die
ich dann in abgeleiteten Klassen überschreiben kann, also z.B.:

class BiggerAddress extends SimpleAddress
{
.....
public static Properties initAddressTypes()
{
// super-Aufrufe gehen ja schon mal eh nicht.
Properties p = new Properties();
p.put("undefined", new Integer(0));
p.put("home", new Integer(1));
p.put("work", new Integer(2));
p.put("delivery", new Integer(3));
p.put("invoice", new Integer(4));
return p;
}

}

So 'ne große Adresse braucht eben mehr Typen.

Da getAddressTypes nun aber in SimpleAddress implementiert ist, bringt auch
der Zugriff auf BiggerAddress.getAddressTypes() nur die Typen von
SimpleAddress.
Super! :-(

In BiggerAddress auch noch mal 'n types deklarieren bringt nix.
Auch nicht, wenn ich dann mittels this.types drauf zugreife.
Muß ich auch getAddressTypes() als static deklarieren?
Dann hätte ich aber das Problem, daß ich natürlich immer auf
BiggerAddress-Instanzen auch als solche zugreifen muß, da ja beim Zugriff
über eine SimpleAddress-Variable deren static Methode aufgerufen wird.

Ist ja irgendwie peinlich, aber ich hab anscheinend 'n Knoten im Hirn.
Da gibt's sicher 'ne vernünftige Lösung für, aber ich komm um's Verrecken
nicht drauf.

Hilfe! :-(
Komme mir vor wie der blutigste Anfänger...
Sascha Raubal
2004-09-14 13:35:16 UTC
Permalink
Grrrr!!!

Kaum fragt man in der NG, schon kommt man selbst noch auf was.
Hab in beiden Klassen eine static Variable samt static
initialisierungs-Funktion gemacht, dann eine ganz normale Instanz-Variable,
und in den Konstruktoren (die ich ja eh immer überschreiben muß) setze ich
die Instanz-Variable auf die Klassen-Variable und gut is.
Kostet nur die eine Referenz.

Also, so läßt sich die Sache zumindest benutzbar machen.

Wenn jemand eine vernünftigere Lösung kennt, von mir aus auch 'n ganz
anderen Weg...?
Torsten Munkelt
2004-09-14 13:45:45 UTC
Permalink
Hallo, Sascha,
Post by Sascha Raubal
class SimpleAddress
{
String street;
String ZIP;
String city;
Integer type;
}
class BiggerAddress extends SimpleAddress
{
String county;
String country;
}
ist das nicht falschherum? Hat nicht eigentlich
jede Adresse County und Country, und bei der
SimpleAddress wird das nur nicht benutzt/angezeigt?
Vielleicht kannst Du ja einen Initialisierer/Importer
und einen Exporter fuer die Attribute schreiben,
der (beim Erstellen) uebergeben wird, und durch
diesen die Funktionalitaet der Klasse Address
anpassen?

Schoene Gruesse - Torsten
Sascha Raubal
2004-09-14 14:17:50 UTC
Permalink
Hi Torsten!
Post by Torsten Munkelt
Post by Sascha Raubal
class SimpleAddress
{
String street;
String ZIP;
String city;
Integer type;
}
class BiggerAddress extends SimpleAddress
{
String county;
String country;
}
ist das nicht falschherum? Hat nicht eigentlich
jede Adresse County und Country, und bei der
SimpleAddress wird das nur nicht benutzt/angezeigt?
In dem Beispiel kann man das sicher so sehen.
Aber es geht letztlich um Projektierbarkeit.
Wenn ich eine Adress-Klasse definiert habe, und irgendwann will jemand
spezielle Adressen, die eben noch ein paar Felder mehr haben, dann will ich
einfach eine Klasse "SuperDuperAddress extends NormalAddress" ableiten und
fertig. Und das selbe gilt dafür, daß z.B. jemand ganz eigene Typen von
Adressen hat.
Post by Torsten Munkelt
Vielleicht kannst Du ja einen Initialisierer/Importer
und einen Exporter fuer die Attribute schreiben,
der (beim Erstellen) uebergeben wird, und durch
diesen die Funktionalitaet der Klasse Address
anpassen?
Meinst Du eine komplett generische Klasse?
Nee, das ist denn doch zu viel des Guten.
Die Typen aus 'nem Bundle oder so einzulesen ginge natürlich. Hab das aber
lieber direkt im Code, sonst pfuscht mir sonstwer in den .properties rum.

Ich wollte halt hauptsächlich deshalb static Variablen nutzen, um den
Platzbedarf etwas einzuschränken.
Wäre ja Schwachsinn, wenn jede Instanz einer Adresse ein ganzes eigenes
Properties-Objekt hält.

Naja, 'n Workaround hab ich.
Torsten Munkelt
2004-09-14 17:29:35 UTC
Permalink
Hallo, Sascha,
Post by Sascha Raubal
Post by Torsten Munkelt
Post by Sascha Raubal
class SimpleAddress
{
String street;
String ZIP;
String city;
Integer type;
}
class BiggerAddress extends SimpleAddress
{
String county;
String country;
}
Vielleicht kannst Du ja einen Initialisierer/Importer
und einen Exporter fuer die Attribute schreiben,
der (beim Erstellen) uebergeben wird, und durch
diesen die Funktionalitaet der Klasse Address
anpassen?
Meinst Du eine komplett generische Klasse?
weiss nicht genau, was Du mit generischer Klasse
meinst, aber ja, Du koenntest eine Klasse schreiben,
der Du zu Beginn sagst, was sie alles fuer Attribute
haben soll.

Du koenntest aber auch zwei innere Interfaces
schreiben, welche extern implementiert werden
und deren Implementierungen die Attribute der
Klasse fuellen und die Attribute der Klasse
liefern. Diese Interfaces koennte es fuer eine
kleine und eine grosse Adresse geben. Und die
implementierenden Klassen koennten gleich
noch die Funktionalitaet enthalten, welche fuer
die Arbeit mit den Attributen notwendig ist,
wie z. B. die Visualisierung. Hoffe, dass ich
mich einigermassen klar ausgedrueckt habe.

Schoene Gruesse - Torsten
Sebastian Scheid
2004-09-14 14:01:09 UTC
Permalink
Post by Sascha Raubal
Hi!
Also, irgendwann treiben mich diese static-Regeln zur Verzweiflung.
Einerseits kann man so herrlich Speicher sparen, wenn eh für alle Instanzen
das gleiche gilt, andererseits hab ich dann Probleme mit Ableitungen.
class SimpleAddress
{
String street;
String ZIP;
String city;
Integer type;
}
class BiggerAddress extends SimpleAddress
{
String county;
String country;
}
Das Feld type soll eine Kennung beinhalten, ob es sich z.B. um eine private
oder geschäftliche Adresse handelt.
Damit man das auch mit halbwegs sprechenden Bezeichnern machen kann, hab ich
class SimpleAddress
{
protected static Properties types = initAddressTypes();
.....
public static Properties initAddressTypes()
{
Properties p = new Properties();
p.put("undefined", new Integer(0));
p.put("home", new Integer(1));
p.put("work", new Integer(2));
return p;
}
public Properties getAddressTypes()
{
return types.clone();
}
}
Hielt mich ja für sooo schlau, das mit 'ner Methode zu initialisieren, die
class BiggerAddress extends SimpleAddress
{
.....
public static Properties initAddressTypes()
{
// super-Aufrufe gehen ja schon mal eh nicht.
Properties p = new Properties();
p.put("undefined", new Integer(0));
p.put("home", new Integer(1));
p.put("work", new Integer(2));
p.put("delivery", new Integer(3));
p.put("invoice", new Integer(4));
return p;
}
}
So 'ne große Adresse braucht eben mehr Typen.
Da getAddressTypes nun aber in SimpleAddress implementiert ist, bringt auch
der Zugriff auf BiggerAddress.getAddressTypes() nur die Typen von
SimpleAddress.
Super! :-(
In BiggerAddress auch noch mal 'n types deklarieren bringt nix.
Auch nicht, wenn ich dann mittels this.types drauf zugreife.
Muß ich auch getAddressTypes() als static deklarieren?
Dann hätte ich aber das Problem, daß ich natürlich immer auf
BiggerAddress-Instanzen auch als solche zugreifen muß, da ja beim Zugriff
über eine SimpleAddress-Variable deren static Methode aufgerufen wird.
Ist ja irgendwie peinlich, aber ich hab anscheinend 'n Knoten im Hirn.
Da gibt's sicher 'ne vernünftige Lösung für, aber ich komm um's Verrecken
nicht drauf.
Sascha Raubal
2004-09-14 14:09:24 UTC
Permalink
Hi Sebastian!
Post by Sascha Raubal
Muß ich auch getAddressTypes() als static deklarieren?
Dann hätte ich aber das Problem, daß ich natürlich immer auf
BiggerAddress-Instanzen auch als solche zugreifen muß, da ja beim Zugriff
über eine SimpleAddress-Variable deren static Methode aufgerufen wird.
Ja, hätte aber nicht den gewünschten Effekt.
Ich möchte auch mal folgendes machen können:

SimpleAddress a = new BiggerAddress();
System.out.println(a.getAddressTypes();

Dies würde mir aber immer die Typen der SimpleAddress liefern.

Hab ja inzwischen zumindest einen Workaround gefunden.
Sebastian Scheid
2004-09-14 14:19:23 UTC
Permalink
Sorry,

jetzt ist mir das schon wieder passiert: Alt+S in OE für senden statt Alt+V
für paste.
Post by Sascha Raubal
Hi!
Also, irgendwann treiben mich diese static-Regeln zur Verzweiflung.
Einerseits kann man so herrlich Speicher sparen, wenn eh für alle Instanzen
das gleiche gilt, andererseits hab ich dann Probleme mit Ableitungen.
class SimpleAddress
{
String street;
String ZIP;
String city;
Integer type;
}
class BiggerAddress extends SimpleAddress
{
String county;
String country;
}
Das Feld type soll eine Kennung beinhalten, ob es sich z.B. um eine private
oder geschäftliche Adresse handelt.
Damit man das auch mit halbwegs sprechenden Bezeichnern machen kann, hab ich
class SimpleAddress
{
protected static Properties types = initAddressTypes();
.....
public static Properties initAddressTypes()
{
Properties p = new Properties();
p.put("undefined", new Integer(0));
p.put("home", new Integer(1));
p.put("work", new Integer(2));
return p;
}
public Properties getAddressTypes()
{
return types.clone();
}
}
Hielt mich ja für sooo schlau, das mit 'ner Methode zu initialisieren, die
class BiggerAddress extends SimpleAddress
{
.....
public static Properties initAddressTypes()
{
// super-Aufrufe gehen ja schon mal eh nicht.
Properties p = new Properties();
p.put("undefined", new Integer(0));
p.put("home", new Integer(1));
p.put("work", new Integer(2));
p.put("delivery", new Integer(3));
p.put("invoice", new Integer(4));
return p;
}
}
So 'ne große Adresse braucht eben mehr Typen.
Da getAddressTypes nun aber in SimpleAddress implementiert ist, bringt auch
der Zugriff auf BiggerAddress.getAddressTypes() nur die Typen von
SimpleAddress.
Super! :-(
In BiggerAddress auch noch mal 'n types deklarieren bringt nix.
Auch nicht, wenn ich dann mittels this.types drauf zugreife.
Du solltest nicht mit this sondern mit BiggerAddress.X drauf zugreifen.
class BiggerAddress extends Address {
protected static Properties types = initAddressTypes();


public static Properties initAddressTypes() {
// super-Aufrufe gehen ja schon mal eh nicht.
Properties p = new Properties();
p.put("undefined", new Integer(0));
p.put("home", new Integer(1));
p.put("work", new Integer(2));
p.put("delivery", new Integer(3));
p.put("invoice", new Integer(4));
return p;
}

public Properties getAddressTypes() {
return types;
}
}



ABER: das Ganze SCHREIT nach State/Strategy-Pattern!
Führe eine zweite Klassenhierarchie mit AddressType als Superklasse ein. Die
Subklassen sind z.B. HomeAddress und WorkAddress.
Die Klasse SimpleAddress bekommt dann ein Feld
private AddressType type;
Dort steht der Typ drin. Den kannst du, wenn du möchtest, sogar zur Laufzeit
ändern, ohne das SimpleAddress-Objekt wechseln zu müssen.

Du kannst dann beliebige neue Typen hinzufügen, indem du die
AddressType-Hierarchie erweiterst.

Schöne Grüße
Sebastian
Sascha Raubal
2004-09-14 14:29:19 UTC
Permalink
Post by Sebastian Scheid
Sorry,
jetzt ist mir das schon wieder passiert: Alt+S in OE für senden statt
Alt+V für paste.
Hoppla, dann hab ich auf was ganz falsches geantwortet. :-)
Post by Sebastian Scheid
Post by Sascha Raubal
In BiggerAddress auch noch mal 'n types deklarieren bringt nix.
Auch nicht, wenn ich dann mittels this.types drauf zugreife.
Du solltest nicht mit this sondern mit BiggerAddress.X drauf zugreifen.
Ich hab ja die Funktion getAddressTypes() in SimpleAddress definiert, nicht
in BiggerAddress.
Post by Sebastian Scheid
class BiggerAddress extends Address {
protected static Properties types = initAddressTypes();
public static Properties initAddressTypes() {
// super-Aufrufe gehen ja schon mal eh nicht.
Properties p = new Properties();
p.put("undefined", new Integer(0));
p.put("home", new Integer(1));
p.put("work", new Integer(2));
p.put("delivery", new Integer(3));
p.put("invoice", new Integer(4));
return p;
}
public Properties getAddressTypes() {
return types;
}
}
Also die getAddressTypes() jedesmal wieder überschreiben?
Da fände ich meine Variante mit der Instanz-Variablen, die im Konstruktor
auf die statische gesetzt wird, aber noch praktischer.
Post by Sebastian Scheid
ABER: das Ganze SCHREIT nach State/Strategy-Pattern!
Wie meinen?
State/Strategy-Pattern?

Irgendwie ist die letzte Zeit wohl einiges an mir vorbeigerauscht.
Post by Sebastian Scheid
Führe eine zweite Klassenhierarchie mit AddressType als Superklasse ein.
Die Subklassen sind z.B. HomeAddress und WorkAddress.
Die Klasse SimpleAddress bekommt dann ein Feld
private AddressType type;
Dort steht der Typ drin. Den kannst du, wenn du möchtest, sogar zur
Laufzeit ändern, ohne das SimpleAddress-Objekt wechseln zu müssen.
Du kannst dann beliebige neue Typen hinzufügen, indem du die
AddressType-Hierarchie erweiterst.
Hmmm...
Eigentlich soll das Feld addressType deshalb ein int sein, weil es in die DB
kommt. Da ist so ein int schon praktisch.

Ich könnte natürlich die Adresstypen auch gleich ganz außerhalb der
Adressklassen halten, in einer Konfiguration, und dann die immer fragen.
Aber eigentlich scheint es natürlicher, wenn ich die Adresse nach den Typen
fragen kann, die sie haben kann.

Früher hab ich die Typen einfach mit "public static final int HOME = 1;"
usw. definiert, aber das ist halt nicht grad flexibel.
Properties kann ich theoretisch zur Laufzeit auswechseln, wenn das mal nötig
ist.
Sebastian Scheid
2004-09-14 14:55:07 UTC
Permalink
Post by Sascha Raubal
Post by Sebastian Scheid
ABER: das Ganze SCHREIT nach State/Strategy-Pattern!
Wie meinen?
State/Strategy-Pattern?
Irgendwie ist die letzte Zeit wohl einiges an mir vorbeigerauscht.
Stichwort: Design Patterns.
Post by Sascha Raubal
Post by Sebastian Scheid
Führe eine zweite Klassenhierarchie mit AddressType als Superklasse ein.
Die Subklassen sind z.B. HomeAddress und WorkAddress.
Die Klasse SimpleAddress bekommt dann ein Feld
private AddressType type;
Dort steht der Typ drin. Den kannst du, wenn du möchtest, sogar zur
Laufzeit ändern, ohne das SimpleAddress-Objekt wechseln zu müssen.
Du kannst dann beliebige neue Typen hinzufügen, indem du die
AddressType-Hierarchie erweiterst.
Hmmm...
Eigentlich soll das Feld addressType deshalb ein int sein, weil es in die DB
kommt. Da ist so ein int schon praktisch.
Aber an dem Typ hängt doch bestimmt noch irgendwas dran: z.B. anderes
Verhalten. Das kannst du in die Typklassen reinstecken. Und wenn es nur eine
Methode getTypeString() ist, die die Namen des Typs ausgibt.
Wenn es sich allein um einen Kennzeichner handelt, reicht ein int wohl aus.
Aber sollte das nicht schon aus den nutzenden Klassen hervorgehen? Wenn du
eine Klasse Person hast, kann die halt je ein Feld für die Home- und
WorkAddress haben:
SimpleAddress homeAddress;
SimpleAddress workAddress;

Wenn die Home und Work-Adressen das gleiche Verhalten haben, wozu brauchst
du dann die Unterscheidung durch das Typfeld?

Gruß
Sebastian
Andree Große
2004-09-15 04:13:53 UTC
Permalink
...
Wenn du eine Klasse Person hast, kann die halt je ein Feld für die Home-
SimpleAddress homeAddress;
SimpleAddress workAddress;
Dieses Verfahren scheint besonders beliebt zu sein. Aber vernünftig ist
es nicht. Eine Person kann n Adressen haben und die gehören in eine
Collection. Und wie willst du denn bei deinem Verfahren die Adressen
in der DB unterscheiden - etwa a'la cityHome, cityWork etc?

An den OP: Für dein Problem implementierst du einen EnumType und
erweiterst deine Adreßklasse um ein solches Feld. Vereinfacht:

class Address
{
private String zip, city, street;
private Country country;
private AddressType type;
}

A.G.
Sascha Raubal
2004-09-15 08:55:50 UTC
Permalink
Hi Andree!
Post by Andree Große
...
Wenn du eine Klasse Person hast, kann die halt je ein Feld für die Home-
SimpleAddress homeAddress;
SimpleAddress workAddress;
Dieses Verfahren scheint besonders beliebt zu sein. Aber vernünftig ist
es nicht. Eine Person kann n Adressen haben und die gehören in eine
Collection. Und wie willst du denn bei deinem Verfahren die Adressen
in der DB unterscheiden - etwa a'la cityHome, cityWork etc?
Eben dieses.
Post by Andree Große
An den OP: Für dein Problem implementierst du einen EnumType und
class Address
{
private String zip, city, street;
private Country country;
private AddressType type;
}
Unter EnumType verstehst Du 'ne Klasse, die java.util.Enumeration
implementiert, nehme ich an.
Weiß jetzt aber im Moment nicht, was mir das an Vorteilen bringen soll.
Okay, ich könnte natürlich die Werte dort innerhalb der Enumeration-Klasse
static machen und dann den diversen Adress-Varianten entsprechende
Varianten der Enumeration mitgeben.
Das selbe Prinzip nutze ich jetzt aber auch schon, die Properties static
machen und dann eine Instanz-Variable darauf setzen.
Nur, daß Properties den Zugriff wesentlich erleichtern, ich muß nur bei der
Revers-Suche (also suche Name für Typ-int) durch eine Enumeration hecheln,
der übliche Fall (int für Name) geht wesentlich simpler.

An sich möchte ich halt schon, daß eine Klasse weiß, welche Typen sie kennen
muß.

Naja, hab ja mal wieder den Fall gehabt, daß ich kurz nach meiner Frage
selbst auf 'ne Lösung gestoßen bin, die für meine Zwecke ganz gut
funktioniert. Aber da stand das Posting schon hier.

Trotzdem Merci!
Andree Große
2004-09-16 04:59:21 UTC
Permalink
Post by Sascha Raubal
Post by Andree Große
Und wie willst du denn bei deinem Verfahren die Adressen
in der DB unterscheiden - etwa a'la cityHome, cityWork etc?
Eben dieses.
Und das ist schlicht der schlechteste Ansatz.
Post by Sascha Raubal
Unter EnumType verstehst Du 'ne Klasse, die java.util.Enumeration
implementiert, nehme ich an.
Nein das hat mit dieser Enumeration nichts zu tun. Es geht um das
Enum Pattern. Alles weitere siehe Threadfortsetzung von Sebastian.

A.G.
Sascha Raubal
2004-09-16 08:29:58 UTC
Permalink
Post by Andree Große
Post by Sascha Raubal
Post by Andree Große
Und wie willst du denn bei deinem Verfahren die Adressen
in der DB unterscheiden - etwa a'la cityHome, cityWork etc?
Eben dieses.
Und das ist schlicht der schlechteste Ansatz.
Das meinte ich ja. Wollte Dir damit nur beipflichten.
Natürlich hab ich die Adressen mit 'ner parentId.
Post by Andree Große
Post by Sascha Raubal
Unter EnumType verstehst Du 'ne Klasse, die java.util.Enumeration
implementiert, nehme ich an.
Nein das hat mit dieser Enumeration nichts zu tun. Es geht um das
Enum Pattern. Alles weitere siehe Threadfortsetzung von Sebastian.
Als Sebastian das Beispiel gebracht hat, hab ich mich wieder an C++-Zeiten
erinnert. Da gibt's ja direkt einen Typ für sowas. Lang, lang ist's her...
Sebastian Scheid
2004-09-16 09:27:43 UTC
Permalink
Post by Sascha Raubal
Post by Andree Große
Post by Sascha Raubal
Unter EnumType verstehst Du 'ne Klasse, die java.util.Enumeration
implementiert, nehme ich an.
Nein das hat mit dieser Enumeration nichts zu tun. Es geht um das
Enum Pattern. Alles weitere siehe Threadfortsetzung von Sebastian.
Als Sebastian das Beispiel gebracht hat, hab ich mich wieder an C++-Zeiten
erinnert. Da gibt's ja direkt einen Typ für sowas. Lang, lang ist's her...
Naja, C++ ist zwar nicht meine Stärke, aber soweit ich weiß sind die enums
dort im Prinzip einfache ints. Sie haben zwar Namen, aber dort wo sie als
Parameter erwartet werden, kannst du wohl genauso ein int einsetzen. Womit
die Typsicherheit wieder dahin ist. Falls Typsicherheit erwünscht ist, sind
sie keine große Hilfe und das typesafe enum pattern müsste in C++ ebenso
realisiert werden.

Grüße
Sebastian

Sebastian Scheid
2004-09-15 09:26:06 UTC
Permalink
Post by Andree Große
...
Wenn du eine Klasse Person hast, kann die halt je ein Feld für die Home-
SimpleAddress homeAddress;
SimpleAddress workAddress;
Dieses Verfahren scheint besonders beliebt zu sein. Aber vernünftig ist
es nicht. Eine Person kann n Adressen haben und die gehören in eine
Collection. Und wie willst du denn bei deinem Verfahren die Adressen
in der DB unterscheiden - etwa a'la cityHome, cityWork etc?
An den OP: Für dein Problem implementierst du einen EnumType und
class Address
{
private String zip, city, street;
private Country country;
private AddressType type;
}
A.G.
Im Prinzip hab ja genau das zwei Postings vorher gesagt. Ok, eine neue
Vererbungshierarchie ist in diesem Fall Overkill, weil der Typ ja kein
großartiges Verhalten übernimmt. Aber man hält sich die Option offen, sie
irgendwann einzuführen, wenn man den Adresstyp eben als Klasse einführt.
Aber das scheint Sascha nicht zu gefallen.
Das Hauptargument für eine Enum Klasse ist ja die compiletime Sicherheit
wenn man es so implementiert (typesafe enum):

public class AddressType {
public final static AddressType HOME_ADDRESS = new AddressType(0);
public final static AddressType WORK_ADDRESS = new AddressType(1);

private static AddressType[] types = new AddressType[] {HOME_ADDRESS,
WORK_ADDRESS};
public static AddressType getTypeForCode(int typeCode) { return
types[typeCode]; } // hier kann man sich natürlich auch ein besseres
Mapping einfallen lassen

private int typeCode;

private AddressType(int typeCode) {this.typeCode = typeCode;}

public int getTypeCode() {return typeCode;}

}


Dabei gibt es also nur noch die Examplare von AddressType, die hier als
Konstanten eingeführt werden.
Überall wo du mit AddressType arbeitest, kannst du dir dann sicher sein,
dass es eine der Konstanten ist.
Und wenn du aus der DB den typint liest und dir mit
AddressType#getTypeForCode() das entsprechende Objekt holst, dann bekommst
du sofort eine RunTimeException, falls in der DB ein ungültiger Wert steht.
Das ist dann zwar erst zur Laufzeit, aber immerhin nah an der Fehlerquelle
(DB) und nicht erst später in einem switch-Statement:
switch(addressType) {
case ...
default: // should never happen. BANG!


Also mir gefällt das so. Vielleicht konnten wir dich, Sascha, ja jetzt
überzeugen :-) Danke Andree für die Vereinfachung auf die Enumklasse.
Manchmal packt man eben die Kanonen aus, wenn man zuviel in Büchern liest
:-)

Gruß
Sebastian
Sascha Raubal
2004-09-15 11:12:01 UTC
Permalink
Hi again!

Mei oh mei, jetzt ist mir klar, was Andree mit dem EnumType meinte.
Irgendwann wußte ich schon mal was darüber...
Post by Sebastian Scheid
Im Prinzip hab ja genau das zwei Postings vorher gesagt. Ok, eine neue
Vererbungshierarchie ist in diesem Fall Overkill, weil der Typ ja kein
großartiges Verhalten übernimmt. Aber man hält sich die Option offen, sie
irgendwann einzuführen, wenn man den Adresstyp eben als Klasse einführt.
Aber das scheint Sascha nicht zu gefallen.
Jaja, manchmal bin ich ziemlich eigen..... ;-)
Post by Sebastian Scheid
Das Hauptargument für eine Enum Klasse ist ja die compiletime Sicherheit
Also, das kingt schon gut, soweit.
Hat allerdings den Nachteil, daß ich dann tatsächlich gezwungen bin, die
AddressType jedesmal neu zu codieren, wenn sich was an den möglichen Typen
ändert. Wenn dann noch die verschiedenen Adress-Arten (SimpleAddress samt
Kinderchens) unterschiedliche Typen zulassen sollen, krieg ich doch wieder
meine Probleme.

Ich möchte außerdem gar nicht zur Compiletime auf die zulässigen Werte
prüfen, sondern zur Runtime. So kann ich z.B. die Liste (bei mir
Properties) der zulässigen Werte gleich zum Programstart mit eigenen Werten
überschreiben und diese z.B. aus einer Konfiguration herauslesen.
Das Überschreiben einer Adress-Klasse wird dann nur nötig, wenn sie auch
wirklich neue Felder hat oder ähnliche Änderungen nötig sind.
Post by Sebastian Scheid
public class AddressType {
public final static AddressType HOME_ADDRESS = new AddressType(0);
public final static AddressType WORK_ADDRESS = new AddressType(1);
private static AddressType[] types = new AddressType[] {HOME_ADDRESS,
WORK_ADDRESS};
public static AddressType getTypeForCode(int typeCode) { return
types[typeCode]; } // hier kann man sich natürlich auch ein besseres
Mapping einfallen lassen
private int typeCode;
private AddressType(int typeCode) {this.typeCode = typeCode;}
public int getTypeCode() {return typeCode;}
}
Als ich's gesehen hab, war mir der Begriff EnumTyp wieder klar.
Post by Sebastian Scheid
Dabei gibt es also nur noch die Examplare von AddressType, die hier als
Konstanten eingeführt werden.
Überall wo du mit AddressType arbeitest, kannst du dir dann sicher sein,
dass es eine der Konstanten ist.
Zur Compiletime.
Post by Sebastian Scheid
Und wenn du aus der DB den typint liest und dir mit
AddressType#getTypeForCode() das entsprechende Objekt holst, dann bekommst
du sofort eine RunTimeException, falls in der DB ein ungültiger Wert
steht. Das ist dann zwar erst zur Laufzeit, aber immerhin nah an der
Fehlerquelle (DB)
Naja, wenn in der DB ein falscher Wert steht, hat mir aber einer kräftig was
vermurkst. Im normalen Betrieb sollte das ja nicht passieren.
Davon ab möchte ich dann nicht gleich eine RuntimeException kriegen, nur
weil das Programm eine bestimmte Adresse nicht mehr so ganz zuordnen kann.
Schlimmstenfalls ist sie dann halt nutzlos geworden.
Post by Sebastian Scheid
switch(addressType) {
case ...
default: // should never happen. BANG!
Ja nee, ein switch kommt da auch nicht hin.

Ich prüfe beim Setzen der Werte (vor dem Speichern) auf deren Zulässigkeit
und schmeiße meine eigene Exception, wenn da jemand Müll setzen will.
Wenn dann tatsächlich in der DB falsche Werte drinstehen, dann muß entweder
jemand an der Config oder der DB rumgebastelt haben.
Post by Sebastian Scheid
Also mir gefällt das so. Vielleicht konnten wir dich, Sascha, ja jetzt
überzeugen :-)
Ist bei mir manchmal etwas schwer, würden Dir meine früheren Kollegen sicher
bestätigen. ;-))

Also, wie gesagt, das Konzept an sich ist mir jetzt klar und sicher auch in
vielen Fällen hilfreich.
Aber ich möchte bei Projekt-spezifischen Erweiterungen/Änderungen möglichst
wenig coden müssen sondern viel in irgendwelchen config-files erledigen
können.
Nur die Vorbelegung, die in diesem Falle eben mal die wichtigsten
Adress-Typen abdecken soll und hoffentlich meist ausreicht, die kommt in
die Klasse rein.

Hab vermutlich das Verwendungsziel usw. in meiner Frage auch nicht richtig
klar gemacht, da ich nur dieses static-Problem im Kopf hatte.
Post by Sebastian Scheid
Danke Andree für die Vereinfachung auf die Enumklasse.
Danke für die Verdeutlichung, was damit gemeint war.
Post by Sebastian Scheid
Manchmal packt man eben die Kanonen aus, wenn man zuviel in Büchern liest
:-)
Und wenn man zu wenig in den Büchern liest, friemelt man sich viel zu oft
irgendwelche eigenen Lösungen zurecht, obwohl's dafür schon was gibt.

Auf jeden Fall merci für die Antworten!
Andree Große
2004-09-16 04:54:10 UTC
Permalink
Post by Sebastian Scheid
Das Hauptargument für eine Enum Klasse ist ja die compiletime Sicherheit
public class AddressType {
public final static AddressType HOME_ADDRESS = new AddressType(0);
public final static AddressType WORK_ADDRESS = new AddressType(1);
private static AddressType[] types = new AddressType[] {HOME_ADDRESS,
WORK_ADDRESS};
public static AddressType getTypeForCode(int typeCode) { return
types[typeCode]; } // hier kann man sich natürlich auch ein besseres
Mapping einfallen lassen
private int typeCode;
private AddressType(int typeCode) {this.typeCode = typeCode;}
public int getTypeCode() {return typeCode;}
}
So würde ich das nicht implementieren. Zum einen bestehen bei mir solche
Enums stets aus key und value a'la new AddressType(0,"Privatanschrift");
Zweitens stört mich das Array - dafür implementiert man eine EnumRange.
Auf dieser werden dann passende finder definiert, in etwa so:

AddressType.getRange().find(int key)
AddressType.getRange().find(String value);

Soll das ganze dynamisch sein, dann nimmt man dafür eine DynamicEnum,
die ihre Werte aus einer einfachen key,value-Tabelle bezieht. Auf Werte
kann dann über die finder zugegriffen werden.

A.G.
Sascha Raubal
2004-09-15 08:38:48 UTC
Permalink
Hi Sebastian!
Post by Sebastian Scheid
Aber an dem Typ hängt doch bestimmt noch irgendwas dran: z.B. anderes
Verhalten. Das kannst du in die Typklassen reinstecken. Und wenn es nur
eine Methode getTypeString() ist, die die Namen des Typs ausgibt.
Wenn es sich allein um einen Kennzeichner handelt, reicht ein int wohl
aus. Aber sollte das nicht schon aus den nutzenden Klassen hervorgehen?
Wenn du eine Klasse Person hast, kann die halt je ein Feld für die Home-
SimpleAddress homeAddress;
SimpleAddress workAddress;
Wenn die Home und Work-Adressen das gleiche Verhalten haben, wozu brauchst
du dann die Unterscheidung durch das Typfeld?
Andree hat das schon angemerkt. 1zuN-Beziehungen.
Die Unterscheidung brauche ich z.B. im folgenden Szenario:
Angenommen, ich liefere Waren an Firmen, die mehrere Filialen oder auch
Lager haben. Also kann die Lieferadresse bei jeder Lieferung eine aus n
möglichen sein. Dementsprechen kennzeichne ich die möglichen Lieferadressen
mit einem bestimmten Typ.
Wenn ich nun einem Auftrag die Lieferadresse zuordnen will, lade ich aus der
Datenbank alle Adressen, die zum einen dem Kunden zugeordnet sind, zum
anderen den Typ Lieferadresse haben.

Adressen sind ja auch nur ein Beispiel. Es gibt eine Menge Fälle, in denn
1zuN-Beziehungen nötig sind.
Lesen Sie weiter auf narkive:
Loading...