# OOP-Style bei Objekten



## DreamArtist (2. Nov 2005)

In unserer Firma findet häufig die Diskussion statt, welche Methode gehören in ein Objekt.
Dabei werden zwei Ansichten vertreten:

Eine einfache Klasse als Beispiel:

*Mietvertrag*
--------------------------------
mieter : Mieter
von : Date
bis : Date
mietObjekt : Object
--------------------------------


Laut Kapselung gibt es zu jedem Attribute eine get und eine set-Methode.

Die Frage wäre aber ob es richtig oder falsch ist z.B.: folgende Methoden in die Klasse zu packen:

speichern()
suchen(Mieter mieter)
suchen(Date date)


Hier gibt es zwei Meinungen.

Meinung 1:

Nein, Objekte kümmern sich um den inneren Zustand nicht um den äusseren.

Meinung 2:

Ja, warum sollte sich ein Objekt nicht selbst suchen können.

Welche Meinung vertretet Ihr?


----------



## Oni (2. Nov 2005)

Bin zwar noch relativ neu auf dem gebiet, aber ich wage trotzdem mal meine meinung zu äußern.

Ich würde miertvertrag als reine daten-klasse(model) sehen und würde z.B. die suche in eine extra klasse packen, der ich dann z.B. eine arraylist mit mietvertragobjekten übergebe, welche dann durchsucht werden.

wäre in meinen augen die schönere lösung, aber wie gesagt, habe da noch nicht so die riesen erfahrung.


----------



## bygones (2. Nov 2005)

versteh nich, was die suchenMieter Methoden im Mietvertrag soll ? Ein Mietvertrag wird doch zwischen einem Vermieter und einem Mieter geschlossen... was soll man da suchen ?


----------



## AlArenal (2. Nov 2005)

In der Regel wird wohl eher entsprechend Meinung 2 umgesetzt. Allerdings gibts auch noch Zwischenformen. Wenn du z.B. in XML speicherst und jedes speicherbare Objekt sich selbst in XML serialisiert, aber eine eigenständige Klasse das Zusammensetzen dieser Fitzelchen übernimmt...

Neben dem philosophischen gibts auch nen praktischen Ansatz und nach dem versucht man die Speichersignatur einer Anwendung möglichst gering zu halten und wenn ich irgendwo eine Sammlung beliebig vieler Instanzen habe, die alle nen Code zum Abspeichern mit sich rumschleppen ist schnell klar, dass es ressourcenschonenender ist, wenn sich eine einzige Klasse darum kümmert...
Das kann aber wieder umgehen, indem man die Methode static macht und die Instanz als Parameter übergibt...

Ich glaub da kann man Bücher drüber schreiben..


----------



## SnooP (2. Nov 2005)

Jo... sehe ich ähnlich... rein inhaltlich hat die Methode ja nicht wirklich etwas mit dem Objekt Mietvertrag zu tun... zwischen Mieter und Vertrag steht eine 1:1 Beziehung... - andere Mietverträge über ein konkretes Mietvertrag zu suchen, halte ich in diesem Fall für unsinnig... - alternative wäre eine zustandslose Klasse mit static-Methoden zum Suchen von solchen Objekten, die man dann überall nutzen kann...

Programmiertechnisch würde ich sagen, dass die Methoden wiederum nix in den Objekten zu suchen haben, weil die Informationen die sie jeweils einsammeln müssen, ganz woanders liegen... die Methode greift also überhaupt nicht auf eigene Datenbestände zu, sondern auf gänzlich andere... dann kann man die Methode nach Fowler auch verlagern und zwar dorthin, wo die Daten liegen...

Die Methode speichern() hab ich erst gar nich verstanden


----------



## DreamArtist (2. Nov 2005)

Details:

Der Mietvertrag liegt in der Datenbank die mittels O/R Mapping gleich das Objekt ausliest, bzw. speichert.
Die Diskussion stellt die Frage ob für das Suchen oder Speichern eine eigene Klasse geschrieben werden muss oder ob diese Methoden in die Klasse Mietvertrag geschrieben werden sollen.

Wobei es ja egal sein soll ob das Objekt in der Datenbank, in einen File oder sonstwo erfasst bzw gespeichert wird.

Der Kern der Frage ist eher ob ein Objekt überhaupt dafür verantwortlich sein soll sich selbst zu suchen oder zu speicher oder sonstige "externe" Aktionen mit sich ausführen "darf".

Der Mietvertrag dient hier nur als Beispiel.

Könnte auch ein Auto sein und die Methode reparieren


----------



## SnooP (2. Nov 2005)

Also jetzt wo ich nochmal hingeguckt hab, könnte zumindest das Speichern wie oben bereits beschrieben sinnig sein... dann könnte man sogar polymorphie nutzen, falls man einfach alle "saveable" Objekte über eine zentrale Methode aufruft, die jeweils die speichern() Methode aufrufen. Könnte aber wie oben ebenfalls gesagt zu sehr viel Overhead führen... müsste man gucken... wäre aber zu vertreten - das ist immerhin ne Aktion, die sich speziell um das Objekt dreht - die Suchen-Methoden imho tun dies nicht.


----------



## DreamArtist (2. Nov 2005)

Man könnte aber auch eine externe public void save(Object obj) schreiben. Wäre dann auch für alle Objekte möglich.

Lösen kann man die Methoden sicher in der Klasse wie auch extern.

Aber was ist das richtige Design?

Laut OOP glaube ich verstanden zu haben das Objekte nur für Ihren inneren Zustand verantwortlich sind. nicht für Ihren äussern. was Sinn macht da auch in der Wirklichkeit sich objekte nicht um den äusseren zustand kümmern.

wenn ich das nun versuche sprachlich zu übersetzen:

ein Mietvertrag prüft ob er ein vonDatum hat --> ok
ein Mietvertrag sucht sich --> nicht ok denn wie kann er suchen wenn er noch nicht existiert


----------



## byte (2. Nov 2005)

DreamArtist hat gesagt.:
			
		

> Der Kern der Frage ist eher ob ein Objekt überhaupt dafür verantwortlich sein soll sich selbst zu suchen oder zu speicher oder sonstige "externe" Aktionen mit sich ausführen "darf".



Welchen Sinn hat es denn, wenn sich ein Objekt selbst sucht? return this; ? ???:L


----------



## Sky (2. Nov 2005)

Hast Du eine Klasse, die all deine Mietverträge verwaltet ? Ich meine, so ein Vertrag steht ja nicht in der Luft !?

Die Klasse, die eine Menge von Mietverträgen hält ist für Dinge wie speichern und suchen zuständig.


----------



## Bleiglanz (2. Nov 2005)

du meinst wahrscheinlich

```
speichern()
static Collection suchen(Mieter mieter)
static Collection suchen(Date date)
```
ich würde dagegen stimmen, weil man in dem Fall das ganze Environment (Datenbank? Datei? Parameter?) dem Mietvertrag als Information mitgeben muss, eine sinnlose Aufblähung

bestenfalls ginge noch

```
speichern(PersistenceEnvironment env)
...
```
aber auch das ist nicht wirklich gut

Also: am besten in eine eigene "Persistenz"-Abstraktionsschicht


----------



## byte (2. Nov 2005)

Es kommt imo auf die Struktur des Programms an. Wenn es wie schon meine Vorredner sagten, einen zentralen Controller gibt, der alle Objekte kennt, dann sollte auch dort eine zentrale Methode das speichern der Objekte übernehmen. Ist die Struktur des Programms jedoch stark hierarchisch aufgebaut, dann macht es imo schon Sinn, z.B. ein Interface zum Speichern von Objekten zu definieren und alle Klassen dieses Interface implementieren zu lassen.

Wenn die Struktur z.B. eine Art Baum ist: A kennt B, C, D. B kennt E,F. C kennt G, H. D kennt I, J, K usw.

Alle Objekte speichern sich selbst und stoßen die Speicherung der Objekte an, die sie kennen. Ausgangspunkt ist in diesem Fall A.


----------



## DreamArtist (2. Nov 2005)

Es sollte ja keine Rolle spielen was ich im hintergrund habe (DB, XML, File,..).
Sondern ob die Methode in die Klasse gehört.
theoretisch könnte die Methode suchen in der Klasse Mietvertrag ja folgend aufgebaut sein:


```
public void sucheMietvertrag(String suchWert){
    Mietvertrag mv = doIt(suchWert);
    mv = sucheRichtigenMietvertrag();
    this = mv;
    
}
```

Wäre es extern würde die Methode ja ähnlich sein:


```
public Mietvertrag sucheMietvertrag(String suchWert){
    Mietvertrag mv =  doIt(suchWert);
    mv = sucheRichtigenMietvertrag();
    return mv;
}
```

doIt() könnte jetzt eine DB-Abfrage durchführen
sucheRichtigenMietvertrag() könnte jetzt ein Gui aufrufen oder ähnliches.


----------



## Sky (2. Nov 2005)

DreamArtist hat gesagt.:
			
		

> ```
> this = mv;
> ```


Und wie erklärst Du deinem Compiler, dass er da mitmachen soll ?
Eine Zuweisung funktioniert nicht, weil "this" gleichwertig ist zu einer final deklarierte Variablen.


----------



## DreamArtist (2. Nov 2005)

Bleiglanz hat gesagt.:
			
		

> du meinst wahrscheinlich
> 
> ```
> speichern()
> ...



Bin Deiner Meinung




			
				byto hat gesagt.:
			
		

> Es kommt imo auf die Struktur des Programms an. Wenn es wie schon meine Vorredner sagten, einen zentralen Controller gibt, der alle Objekte kennt, dann sollte auch dort eine zentrale Methode das speichern der Objekte übernehmen. Ist die Struktur des Programms jedoch stark hierarchisch aufgebaut, dann macht es imo schon Sinn, z.B. ein Interface zum Speichern von Objekten zu definieren und alle Klassen dieses Interface implementieren zu lassen.
> 
> Wenn die Struktur z.B. eine Art Baum ist: A kennt B, C, D. B kennt E,F. C kennt G, H. D kennt I, J, K usw.
> 
> Alle Objekte speichern sich selbst und stoßen die Speicherung der Objekte an, die sie kennen. Ausgangspunkt ist in diesem Fall A.




Wie Bleiglanz aber sagte müsste jede Klasse die Information speichern.


Es sollte jetzt auch nicht Rücksicht auf den zusätzlichen Aufwand ("Persistenz"-Abstraktionsschicht) genommen werden sondern nur welchen Weg Ihr wählt und warum.

Bin voll Begeistert über die rege Teilnahme!


----------



## DreamArtist (2. Nov 2005)

Sky hat gesagt.:
			
		

> DreamArtist hat gesagt.:
> 
> 
> 
> ...




Aber wenn dann z.B.:


```
public class Mietvertrag {

	private static Mietvertrag mv = new Mietvertrag();
	
	private Mietvertrag(){
		
	}	

	public Mietvertrag sucheMietvertrag(String suchWert){
		return doIt(suchWert);
	}
	
	private Mietvertrag doIt(String suchWert){
		//tut etwas
		//Setzt die Variablen
		return new Mietvertrag();
	}
}
```

Aber es sollte ja nicht um die implementierung der Methoden gehen sondern wo die Methode hingehören würde :wink:


----------



## byte (2. Nov 2005)

DreamArtist hat gesagt.:
			
		

> byto hat gesagt.:
> 
> 
> 
> ...




Ja, jedes zu speichernde Objekt müsste das Interface implementieren. Es ist also quasi redundante Information in jedem Objekt enthalten. Aber wie willst Du sonst alle Objekte eines Programms speichern, wenn es nicht eine zentrale Stelle gibt, der alle Objekte bekannt sind? Man müsste sich sonst extra eine zentrale Klasse erzeugen, die als Controller fungiert und eine Referenz auf alle Objekte bekommt. Oder man löst es eben wie oben angesprochen, was in so einem Fall meiner Meinung nach die schönere Lösung ist.

Aber ich schließe mich den anderen auf jeden Fall an: Wenn es eine zentrale Klasse gibt, die alle Objekte kennt, dann sollte auf jeden Fall auch diese Klasse die Speicherung der Objekte übernehmen.

Eine Suchmethode direkt im Mietvertrag halte ich für sinnlos.


PS: Hab mich bei der Umfrage verklickt! :roll:  :bae:


----------



## DreamArtist (2. Nov 2005)

Reflection und zu allen Werten die gespeichert werden, Methode in Bean-Konvention schreiben (get und set Methoden)

ps: was hattest denn geklickt?


----------



## Bleiglanz (2. Nov 2005)

```
// in der Klasse Mietvertrag
speichern()
static Collection suchen(Mieter mieter)
static Collection suchen(Date date)
```

a) unter Umständen muss "Mietvertrag" java.sql.Zeugs importieren, das ist irgendwie unschön

b) man kann die Klasse nicht mehr vollständig testen, ohne gleich eine Datenbank mit aufzustellen

c) die Kontextinformationen (welche DB? usw.) müssen irgendwo übergeben werden, aber weil die such-Methoden aus logischer Sicht static sein müssen führt das erst recht zu einem Schlamassel

d) das alles ist "Boilerplate" Code, den man nicht zigmal in jeder persistenzfähigen Klasse wiederholen sollte...

e) manchmal braucht man Transaktionen, aber wie soll das gehen wenn ich 

```
mieter.save();
   mietvertrag.save();
```
aufrufe -> wer ist in dem Fall für die Transaktionsgrenzen und das commit zuständig? Wer öffnet und schliesst die Connection? usw.

und:

vor ein paar Jahren hat es sich vielleicht noch gelohnt, die Frage zu diskutieren; heute gibt es O/R Mapper aller Art die genau dieses Problem lösen


----------



## DreamArtist (5. Nov 2005)

Bevor der Thread einzuschlafen droht wage ich eine Reanimierung.
Gibt es zu dieser Umfrage noch Meinungen?


----------



## helium (5. Nov 2005)

> Laut Kapselung gibt es zu jedem Attribute eine get und eine set-Methode.


Totaler Unfug!  :bloed:


----------



## Beni (5. Nov 2005)

Also ich würde ja ein paar hübsche Factories basteln (ein Interface mit Methoden "void store( Bla bla ), "Bla load()" ), um die Dinger zu speichern/laden. Dann kann man auch einen Satz Factories für XML, einen Satz für SQL, etc... machen.

helium hat recht, eigentlich sind get/set-Methoden nicht das wahre, sie heben das "private" ja wieder auf. Andererseits funktioniert ein Programm so ganz ohne Referenzen, die ersetzt und abgerufen werden können, nicht (ein JTable ohne setModel, naja :wink.


----------



## bygones (5. Nov 2005)

helium hat gesagt.:
			
		

> > Laut Kapselung gibt es zu jedem Attribute eine get und eine set-Methode.
> 
> 
> Totaler Unfug!  :bloed:


es macht sich immer gut - Behauptungen auch zu erklären.. sie wirken sonst ziemlich "ich red mal was her"...

ne Verallgemeinerung lässt sich z.b. nicht machen - so können getter bzw. setter Methoden so implementiert sein, dass sie der Kapselung nicht widersprechen (Immutables z.b.)


----------



## L-ectron-X (6. Nov 2005)

Beni hat gesagt.:
			
		

> helium hat recht, eigentlich sind get/set-Methoden nicht das wahre, sie heben das "private" ja wieder auf.


Aber doch nur wo du, als Programmierer, es zulässt. Kein Mensch zwingt dich solche Methoden zu implementieren.
Eine public-Variable dagegen ist immer dem Vollzugriff ausgesetzt.


----------



## bygones (6. Nov 2005)

L-ectron-X hat gesagt.:
			
		

> Beni hat gesagt.:
> 
> 
> 
> ...


jup - wie ich auch sagte 

so - nun aber ins Bett... ist schon spät für dein Alter  :lol:  :roll:


----------



## Oni (6. Nov 2005)

Beni hat gesagt.:
			
		

> helium hat recht, eigentlich sind get/set-Methoden nicht das wahre, sie heben das "private" ja wieder auf. .



aber irgendwie muss man doch an die daten (private instanzvariablen)eines objekt kommen können. da sind getter und setter methoden doch die "sauberste" lösung, oder gibt es ne bessere?  :bahnhof:


----------



## bygones (6. Nov 2005)

Oni hat gesagt.:
			
		

> Beni hat gesagt.:
> 
> 
> 
> ...


jein....

wenn z.b. ein Objekt als Variable hast und die per get einfach so zurückgibst, kann der client damit machen was er will, da änderungen sich direkt auch auf die Instanzvariable auswirkt. folglich gibt es keine wahre Kapselung mehr. Daher sollte man jedes, wenn möglich, Objekt Immutable machen. Des Weiteren sollte man sich fragen, was der client mit dem Objekt machen soll und vll nur solche Schnittstellen zur Verfügung stellen, so dass sets nur die Klasse, die das Objekt hält, direkten Zugriff auf das Objekt hat....


----------



## Oni (6. Nov 2005)

hmm, 

also, wenn ich ein objekt mit einer instanzvariablen habe und einer get methode. lese den wert in mit einem anderen objekt aus und mache etwas damit, dann verändert sich doich nicht der wert im objekt oder? hab das mal kurz getest mit dem code unten. das ist es zumindest nicht der fall oder habe ich da etwas falsch verstanden??


```
public class Bla{

  private int myInt = 10;   

  public int getMyInt(){
      	  return myInt;
      }
}


----


public class MachWas{  

  public MachWas(Bla bla){
            int x = bla.getMyInt();
            x = x + 5;
            System.out.println("x = " + x); // 15
            System.out.println(bla.getMyInt()); // 10 
       }


   public static void main(String[] args){
        Bla bla = new Bla();
	   new MachWas(bla);

     }
}
```


----------



## SnooP (6. Nov 2005)

Stopp... du verwechselst primitive Typen (int, double) mit Referenztypen wie es in Java automatisch alle Objekte sind (String, MachWas,...).

Wenn du ein Objekt einer Klasse erstellst und einer Methode übergibst in der Methode auf das Objekt zugreifst und Werte veränderst, ändern die sich nicht nur innerhalb der Methode sondern überall wo auf die Referenz dieses Objektes zugegriffen wird! D.h. wenn du der Methode das Objekt übergibst, wird keine Kopie erstellt!

Wenn du ein Objekt "immutable" machst, bedeutet es, dass es nach der Erstellung nicht mehr verändert werden kann, sodass bei dem Versuch oben auf das Objekt zuzugreifen ein entsprechender Fehler auftritt... - beispiele sind Strings oder Integer (aller Number-Typen in Java). 

Dennoch ist es ja durchaus nen Vorteil, wenn man auf Referenzen innerhalb von Methoden zugreifen kann - wenn man denn tatsächlich das Urobjekt verändern möchte... man sollte sich nur bewusst machen, was man da tut - unter Umständen passiert dann auch etwas was man gerne "Seiteneffekt" nennt... 

Schlechter Stil sind z.B. Methoden die ein Objekt zurückgeben, eine übergebene Referenz aber ebenfalls verändern und nicht nur das Objekt was am Ende zurückgegeben wird... schöner ist, wenn man an der Signatur der Methode schon erkennen kann, was passiert und das man sicher sein kann, dass der Aufruf keine Seiteneffekte an anderer Stelle mitsichbringt.
Aber wenn man quick&dirty programmiert kann sowas auch mal vorkommen  - man sollte sich das nur klar machen...


----------



## Oni (6. Nov 2005)

ok danke, das mit objekten ist klar.
war mit meinen gedanken jetzt nur bei den primitiven daten typen und deswegen leicht verwirrt


----------



## helium (6. Nov 2005)

Also wenn eure Klassen tatsächlich so aussehen, dass sie Größtenteils eine Sammlung von Variablen sind, auf die man durchgehend mit Settern und Gettern zugreiffen kann, dann ist das nicht weit vom Programmieren in C entfernt und hat recht wenig mit OOP und vor allem Kapseln zu tun.

Sicherlich gibt es Dinge, wo genau das das sinnvollste ist. Aber in dre Regel ist das absolut nicht der Fall. Es geht doch gerade darum zu abstrahieren. Welche Instanzvariablen jetzt tatsächlich in der Klasse sind, hat niemanden zu interessieren und sollte sich auch jederzeit ändern dürfen, ohne dass sich die Schnittstelle der Klasse verändert. Wenn ich einfach für jede Instanzvariable einen Getter und einen Setter schreibe ist das ganze sehr steif und Änderungen versuchen unheimliche Probleme.

Guckt euch mal die Klassen aus dem java-eigenen Framework an. Ich nehme jetzt mal irgend 'ne x-beliebige: LinkedList. Findet ihr da auch nur einen Setter oder Getter, um auf eine Instanzvariable zuzugreifen? Niemand kann da auf die Knoten der verkettenen Liste direkt zugreifen. Das braucht und will auch keiner. Dennoch handelt es sich um eine voll funktionsfähige und sinnvoll einsetzbare Klasse.

Ich weiß nicht, ob es eine Instanzvariable gibt, die die Anzahl der Knoten speichert oder ob size() jedesmal die Knoten durchzählt. Das ist bei der Verwendung auch nicht wichtig.


----------



## SnooP (6. Nov 2005)

Naja sinnigerweise hat man meist eher mehr get-Methoden als set... idealerweise ändert eine Klasse ihre Zustände ja selbsttätig und wird nicht von außen per set in einen solchen direkt verfrachtet...
Dennoch gibt es auch Klassen wo genau das notwendig ist... bestimmte Klassen müssen entsprechend konfiguriert werden bzw. ihr Verhalten durch Einstellungen versch. Instanzvariablen ändern... die müssen von außen gesetzt und gelesen werden können... 
Von daher.. braucht man dann doch manchmal auch irgendwie 

Großes Beispiel... Konfigurationsobjekte in Form von JavaBeans... Also Klassen die lediglich aus get/set Methoden und Feldern bestehen... benutze ich gerade als ein Art "struct" Ersatz... sprich die Dinger sollen tatsächlich nur Daten speichern...


----------



## Oni (6. Nov 2005)

das mit den getter /setter methoden verwende ich eigentlich fast nur bei modell klassen, weil irgendwo muss man ja die daten speichern und verändern können. 
das die anderen klassen nicht nur aus setter / getter methoden bestehen ist klar.

z.b.:

```
public class Mitarbeiter{

  private int alter;
  private String nachname;
  private String vorname; 

  usw..

  getter / setter

}
```


----------



## DreamArtist (7. Nov 2005)

Noch kurz zu den set und getMethoden,

eine Klasse muß ja nicht nur aus Variablen bestehen die öffentlich zugänglich sind.
Aber für jene die es sein sollen biete ich public Methoden an um sie im Objekt überprüfen zu können ob die Daten die ich eingebe auch der logischen Struktur des Objektes entsprechen.

Und das ich bei einer Collection eher add als set verwende scheint ja auch vernünftig da es sich in der Collection ja um ein Objekt handelt und von außen nicht einfach die Collection gesetzt werden soll da es sich in diesen Fall ja um eine handelt. (War das jetzt noch verständlich  :bahnhof: )

Die Kapselung sagt ja nicht das alle Attribute private sein müssen und für alle Attribute getter und setter zur Verfügung gestellt werden müssen. Aber für Attribute die direkt den inneren Zustand bestimmen müssen diese her.

Aber zurück zum Sinn dieses Threads: 
*Gehören die Methoden speichern(), suchen(Mieter mieter), suchen(Date date) zum Objekt Mietvertrag?*


----------



## helium (11. Nov 2005)

Oni hat gesagt.:
			
		

> das mit den getter /setter methoden verwende ich eigentlich fast nur bei modell klassen, weil irgendwo muss man ja die daten speichern und verändern können.
> das die anderen klassen nicht nur aus setter / getter methoden bestehen ist klar.
> 
> z.b.:
> ...



Speichere statt des alers das Geburtsdatum. Das ändert sich nicht und du brauchst keinen Setter dafür, da es per C'tor initialisiert werden kann.




> Und das ich bei einer Collection eher add als set verwende scheint ja auch vernünftig da es sich in der Collection ja um ein Objekt handelt und von außen nicht einfach die Collection gesetzt werden soll da es sich in diesen Fall ja um eine handelt. (War das jetzt noch verständlich  )



Der Name ist schieß egal. Es handelt sich technisch gesehen nicht um einene Setter. Da wird nicht eine Variable auf einen Wert gesetzt, der übergeben wurde und möglicherwise vorher auf Gültigkeit getestet wurde, sondern es wird ein Knoten der den neuen Wert trägt erzeugt, der bisher letzte Knoten wird so verändert, das er auf diesen neuen Knoten verweiset, ...


----------



## Oni (12. Nov 2005)

das war nur ein beispiel, mit dem alter.

aber auch fürs geburtsdatum würde ich einen setter machen. weil wenn die person angelegt wird und man vertippt sich(falsches datum)kann man sonst den ganzen datensatz neu anlegen. (datensatz löschen neu erstellen) und vielleicht fällt einem das erst wochen später auf...


----------

