Datenmodell aus ArrayListen ?

Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hi,

ich überlege ob folgendes Datenmodell sinnvoll ist:
Code:
public class Mitglieder {
	private ArrayList<Person> personen = new ArrayList<Person>();
	int mitgliedsID;
}

public class Person{
	private ArrayList<BankDaten> bankdaten= new ArrayList<BankDaten>();
	String name, vorname;
	public ArrayList<BankDaten> getBankdaten() {
		return bankdaten;
	}
}

public class BankDaten{
	String bankname;
	int kontonr;
	int blz;	
}

In Mitglieder werden Personen gespeichert. Jede Person kann eine oder mehrere BankDaten haben.
Ein solches Datenmodell lässt sich relativ einfach bauen, jedoch hat es seine Nachteile (wie ich gerade feststellen muss :-/).
Man kann nicht direkt über einen Index auf bestimmte Werte zugreifen sondern muss jedesmal suchen:
Will man beispielsweise die BankDaten von Person "Mustermann", dann muss man eine solche Verrenkung machen:
Code:
	public ArrayList<BankDaten> getBankDaten(String name){
		
		ArrayList<BankDaten> daten = null;
		for(int i=0;i<personen.size();i++){
			if(personen.get(i).name.equals(name)){
				daten = personen.get(i).getBankdaten();
			}
		}
		return daten;
	}

Aber was soll ich sonst nehmen anstatt ArrayListen? Oder mache ich einen ganz grundsätzlichen Fehler?
 

HLX

Top Contributor
Du könntest eine HashMap verwenden. Schlüssel ist die Person, als Wert hinterlegst du die ArrayList mit dessen Bankdaten.

Edit: bei Verwendung eines eigenen Objekttyps als Schlüssel musst du dessen equals- und hashCode-Methode überschreiben
 

KSG9|sebastian

Top Contributor
Aber sehr schön ist sowas halt auch nicht.
Auserdem musst du ja auch den normalen Use-Case bedenken:

1. Alle Personen anzeigen
2. Eine Person auswählen
3. Zu der ausgewählten Person die Bankdaten anzeigen

Hier hast du die Person eh schon an der Hand, somit fällt das suchen flach.

Fall 2:

1. Eine Person suchen anhand einer PersonenNummer, Name, Adresse u.s.w.
2. Zur gefundenen Person die Bankdaten anzeigen

In dem Fall bringt dir eine Map nichts, weil man nicht nur nach dem Namen suchen kann.
Als nächstes kannst du den Namen nicht als Schlüssel in der Map verwenden, da es sicher einen Hans Meier auch 3x geben kann.
Somit müsstest du z.B. eine Personennummer verwenden. Aber das hilft dir dann auch nicht weiter da über die Personennummer eher selten gesucht wird.
Performancetechnisch bringt dir der Weg über die Map auch nix.

Somit ne Liste oder ein Set verwenden und eben über die entsprechenden Elemente drüberlaufen.

Gruß Sebastian
 
G

Guest

Gast
KSG9|sebastian hat gesagt.:
Performancetechnisch bringt dir der Weg über die Map auch nix.
Performance spielt erstmal eine untergeordnete Rolle.

KSG9|sebastian hat gesagt.:
Somit ne Liste oder ein Set verwenden und eben über die entsprechenden Elemente drüberlaufen.
Also ist mein Weg über die ArrayListen schon gut so? Dachte es gäbe da vielleicht etwas Besseres, denn schön ist das mit dem ewigen Durchsuchen der Listen ja nicht gerade...
 

Marco13

Top Contributor
Wenn es um solche Modellierungsfragen geht, noch eine Nebenbemerkung:
Code:
public ArrayList<BankDaten> getBankdaten() 
{
      return bankdaten;
}
Das ist ziemlich "gefährlich" (also, in mancher Hinsicht unschön). Man legt sich dort auf eine Implementierung fest. Es sollte besser
Code:
public List<BankDaten> getBankdaten() 
{
      return bankdaten;
}
heißen. Aber das ist immernoch suboptimal: Man gestattet ziemlich fiesen Zugriff auf die Bankdaten. Jeder Idiot kann dort Änderungen machen:
Code:
class Betrüger extends Person
{
    void betrüge(Person person)
    {  
        List<Bankdaten> geklaut = person.getBankdaten();
        this.bankdaten.addAll(geklaut);
        person.getBankdaten().removeAll(); // Weg sind sie...
    }
}
(Schönes Beispiel, gell? :D :wink: )

"Sicherer" wäre sowas wie
Code:
class Person
{

    public int getAnzahlBankdaten() { return bankdaten.size(); }
    public Bankdaten getBankdaten(int index) { return bankdaten.get(index); }

    // Wenn's sein muss - aber nur zur Vedeutlichung, "sicher" ist sowas natürlich nicht:
    private String passwort = "Hallo";
    public Bankdaten removeBankdaten(int index, String passwort) 
    { 
         if (!this.passwort.equals(passwort))
         {
             System.out.println("F*** dich!");
             return;
         }
         bankdaten.remove(index); 
    }
}
 
G

Gast

Gast
Hi Marco,

das Beispiel hab ich nur erfunden um mein Problem (ArrayList in ArrayList) zu verdeutlichen. Ich selbst arbeite mit unkritischen Daten.

Dennoch bleibt die Frage ob das nicht besser geht. Dieses ewige Durchsuchen der Listen kann ja nicht das Gelbe vom Ei sein. Oder würdet ihr das auch mit (Array)Listen modellieren?
 

Marco13

Top Contributor
Ja, eine Map<String, Person> nameZuPerson wäre doch in Ordnung!? Was spricht denn dagegen? (Davon ausgehend, dass Personen IMMER unterschiedliche Namen haben (aber wenn das nicht der Fall ist, kommt auch bei der aktuellen Methode was beliebiges raus)).
 

KSG9|sebastian

Top Contributor
Das wird eben so modelliert. Und ich versteh dein Problem immernoch nicht. Warum "ewiges gesuche"?

Meist gehst du doch nur eine Ebene tiefer im Datenmodel, somit ist es max. eine Suchoperation.

- von allen Mitgliedern geht man auf eine Person
- von dieser einen Person geht man auf ein Bankkonto

Im ersten Schritt musst du 1x suchen (nämlich nach ner Person anhand von irgendwelchen Attributen).
Im zweiten Schritt werden z.B. alle Bankkonten angezeigt und der User wählt eines aus. Somit entfällt hier das "suchen im Code".

Wenn du natürlich solche Methoden wie
Code:
public void abheben(int personenNr, int kontoNr, double betrag){

}

machen willst musst du natürlich suchen. Allerdings machen solche Methoden in den allermeisten fällen keinen Sinn, siehe auch Coupling und Cohesion.

Es ist auch nicht Sinn der Sache das die Klasse Mitglieder weiß wie ein Bankkonto aussieht oder wie es Geld an einem Bankkonto abbuchen kann. Diese Logik gehört in den Controller, du baust das in die Modelklassen. Das ist schlechtes Anwendungsdesign.
 

KSG9|sebastian

Top Contributor
Marco13 hat gesagt.:
Ja, eine Map<String, Person> nameZuPerson wäre doch in Ordnung!? Was spricht denn dagegen? (Davon ausgehend, dass Personen IMMER unterschiedliche Namen haben (aber wenn das nicht der Fall ist, kommt auch bei der aktuellen Methode was beliebiges raus)).

In ner Anwendung in der 10 Personen gepflegt werden mag das ja noch funktionieren. Aber auch nur dann wenn eine Person NUR über den Namen identifiziert wird. Nächster Nachteil: Sobald du eine Person suchen willst (also sowas wie *Müller) musst du über das keySet() laufen und vergleichen. Das ist Performancetechnisch so ziemlich das langsamste was man mit ner Map anstellen kann.


** Edit **
Nebenbei ist es der anerkannte Weg sowas über Collections oder Sets abzubilden. Und wenn du das ganze mal ausprogrammierst dann wirst du merken dass ne Map mehr Nach- als Vorteile bringt. Alleine die Persistierung von solchen Objekten wird schon fast zum Genickbruch führen.
 
G

Guest

Gast
KSG9|sebastian hat gesagt.:
Wenn du natürlich solche Methoden wie
Code:
public void abheben(int personenNr, int kontoNr, double betrag){

}

machen willst musst du natürlich suchen. Allerdings machen solche Methoden in den allermeisten fällen keinen Sinn, siehe auch Coupling und Cohesion.

Es ist auch nicht Sinn der Sache das die Klasse Mitglieder weiß wie ein Bankkonto aussieht oder wie es Geld an einem Bankkonto abbuchen kann.

Ja ich würde gerne auch solche Abfragen machen wie z.B. "Welche Kunden sind bei Bank X"..

KSG9|sebastian hat gesagt.:
Diese Logik gehört in den Controller, du baust das in die Modelklassen. Das ist schlechtes Anwendungsdesign.
Wie würde denn ein solcher Controller für die Modellklassen aussehen?

KSG9|sebastian hat gesagt.:
Nebenbei ist es der anerkannte Weg sowas über Collections oder Sets abzubilden. Und wenn du das ganze mal ausprogrammierst dann wirst du merken dass ne Map mehr Nach- als Vorteile bringt. Alleine die Persistierung von solchen Objekten wird schon fast zum Genickbruch führen.
Hast vielleicht dazu ein simples Beispiel, da ich momentan nicht weiß, wie du das mit Collections abbilden willst bzw. welchen Vorteil das hat.
 

HLX

Top Contributor
KSG9|sebastian hat gesagt.:
Diese Logik gehört in den Controller, du baust das in die Modelklassen. Das ist schlechtes Anwendungsdesign.

Dem muss ich widersprechen. Diese Logik ist Anwendungslogik und somit dem Model zuzuordnen. Der Controller dient lediglich der Anwendungssteuerung und darf Logik-Operationen anstoßen und dessen Ergebnis verarbeiten bzw. die Fehlerbehandlung durchführen. Das liegt u.a. daran, dass sich der Controller aufgrund der GUI-Steuerung i.d.R. schlecht von einer GUI-Technologie trennen lässt und somit nicht für andere grafische Oberflächen wiederverwendbar ist. Wiederverwendbare Logik gehört somit ins Backend --> Model.

Deiner übrigen Ausführung (auch hinsichtlich meines Vorschlages s.o.) stimme ich zu.
 

KSG9|sebastian

Top Contributor
HLX hat gesagt.:
KSG9|sebastian hat gesagt.:
Diese Logik gehört in den Controller, du baust das in die Modelklassen. Das ist schlechtes Anwendungsdesign.

Dem muss ich widersprechen. Diese Logik ist Anwendungslogik und somit dem Model zuzuordnen. Der Controller dient lediglich der Anwendungssteuerung und darf Logik-Operationen anstoßen und dessen Ergebnis verarbeiten bzw. die Fehlerbehandlung durchführen. Das liegt u.a. daran, dass sich der Controller aufgrund der GUI-Steuerung i.d.R. schlecht von einer GUI-Technologie trennen lässt und somit nicht für andere grafische Oberflächen wiederverwendbar ist. Wiederverwendbare Logik gehört somit ins Backend --> Model.

Deiner übrigen Ausführung (auch hinsichtlich meines Vorschlages s.o.) stimme ich zu.

Ich hab mich etwas schlecht ausgedrückt. Die Logik um durch die verschiedenen Ebenen zu navigieren gehört natürlich ins Model.

Aber eine Methode getUmsatz(String bankName, String personenName, int kontonr) gehört nicht in die Klasse Bank oder sonstwohin. Sowas sollte man wenn überhaupt in eine andere Klasse auslagern.

Was für ein simples Beispiel hättest du denn gerne?

Code:
class PersonenVerwaltung{
  private List<Person> personen;

  public Person getPerson(int pNr){
     Person p = null;
     for(Person pers : personen){
        if(pers.getPersonenNummer() == pNr){
           p = pers;
           break;
        }
     }
     return p;
  }

  // entsprechende addPerson, deletePerson ... Methoden
}

class Person{
   private List<Adresse> adresse;
   
   // hier auch wieder entsprechende addAdresse, getAdresse u.s.w. Methoden
}

Das ist genauso sehr oder wenig umständlich wie mit Maps zu arbeiten. Nur dass du bei Maps recht schnell Workarounds verwenden muss und wenn es blöd läuft die komplette Logik neu machen musst.

Die Logik um eine Person zu suchen wird meist auf Server-Seite anhand der Persistenzschicht abgebildet.
Es macht wenig Sinn 15000 Personen zu laden wenn nur 3 benötigt werden. Deshalb die Suche über die Persistenzschicht und die Ergebnisse zurückgeben.
Eine findXYZ-Methode macht da meist wenig Sinn.
 
G

Gast

Gast
Danke für das Beispiel!

Nach meinem Wissen liegt die Persistenzschicht zwischen den Daten und der Anwedungslogik. Was du hier aber genau mit Persistenzschicht meinst verstehe ich nicht ganz.

Eine Datenbank wird für die Anwendung nicht eingesetzt, da die Anzahl der Daten überschaubar ist. Dennoch möchte ich gerne beliebige Abfragen auf den Daten durchführen. Beispiel:
Welche Personen wohnen in der Stadt XY?

Meinst du mit Persistenzschicht, dass ich ein Datenmodell wie das in deinem Beispiel verwende und dann eine zusäztliche Schicht/Klasse baue, die eben solche Methoden, wie getPersonenInStadt(String stadt) anbietet und die entsprechenden Methoden implementiert. Also dass solche, mehrere Klassen betreffenden Methoden nicht in der Klasse PersonenVerwaltung definiert sein sollten?
 

KSG9|sebastian

Top Contributor
Persistenzschicht ist der Teil welcher dein Datenmodel in irgendeiner Form speichert (meist in einer Datenbank oder auch in XML-Dateien).

Wie werden die Daten bei dir gespeichert? Gar nicht? Falls ja musst du eben im Datenmodel suchen.

Du kannst dir die benötigten Sucher-Methoden auslagern, z.B. so um eine Person in einer Stadt zu finden.
Code:
public class SearchUtils{
   public List<Person> findPersonInTown(int plz, List<Person> persons){
      List<Person> results = new ArrayList<Person>();
      for(Person person : persons){
          for(Adresse addy : person.getAdresse()){
             if(addy.getPlz() == plz){
                 results.add(person);
             }
          }
      }
   }
   return results;
}
 
G

Gast

Gast
Hi,

nein die Daten werden nicht gespeichert. Sie werden einmal aus einer XML Datei eingelesen und in ein -- noch nicht vorhandenes -- Datenmodell überführt.

Wenn ich jetzt aber deine Klasse PersonenVerwaltung und die dazugehörige Klasse SearchUtils ansehe, dann ist der Unterschied zu meinem ersten Modell doch gar nicht so groß, außer, dass du in den jeweiligen Klasse nur die die Klasse betreffenden Methoden hast und dann eine extra Klasse die darauf komplexere Methoden ausführt. Oder übersehe ich da was?
Damit du mich richtig verstehst: Ich würde das Datenmodell gerne von Anfang an richtig designen um spätere Überaschungen zu vermeiden. Ist der Weg, den du da beschreibst, also ein anerkannter Weg das zu lösen?
 
M

maki

Gast
Ich hör immer nur "Datenmodell"... die 80'er/90'er sind doch längst vorbei und hier handelt es sich nicht um eine ER Tapete, sollte eigentlich ein Domänenmodell sein.

Das mit der Persistenzschicht ist schon richtig, solltest du auf jedenfall hinter Interfaces kapseln, so dass du zum Schluss die SearchUtils nicht mehr zB. aus der GUI aufrufst, sondern eine Klasse hast, die sich darum kümmert.
 
G

Guest

Gast
KSG9|sebastian hat gesagt.:
Gast hat gesagt.:
Hi,
Damit du mich richtig verstehst: Ich würde das Datenmodell gerne von Anfang an richtig designen um spätere Überaschungen zu vermeiden. Ist der Weg, den du da beschreibst, also ein anerkannter Weg das zu lösen?

Ja, das wäre ein korrekter Weg es zu lösen.
Ok, dann werd ich das jetzt so versuchen. Vielen Dank nochmal für deine Hilfe!

maki hat gesagt.:
Das mit der Persistenzschicht ist schon richtig, solltest du auf jedenfall hinter Interfaces kapseln
Wie meinst du das genau? Ein Interface PersonenVerwaltungsInterface, das alle Methoden beschreibt, die man auf der Personenverwaltung ausführen kann?
maki hat gesagt.:
so dass du zum Schluss die SearchUtils nicht mehr zB. aus der GUI aufrufst, sondern eine Klasse hast, die sich darum kümmert.
Das verstehe ich nicht. Irgendwie muss ich ja von der GUI aus die Methoden aufrufen...
 

KSG9|sebastian

Top Contributor
Mit abkapseln ist sowas gemeint:

Code:
public interface IPersistenceManager{
   public void savePerson(Person p) throws DBException;

   public boolean deletePerson(Person p) throws DBException;

   public List<Person> getAllPersons() throws DBException;
..
}


public class XMLPersistenceManager implements IPersistenceManager{
// implementierung
}

Die GUI bzw. der Controller kennt im besten Fall nur das Interface IPersistenceManager. Die konkrete Implementierung (hier: XMLPersistenceManager) wird per DependencyInjection erzeugt. Notfalls über nen statischen Initializer in Abhängigkeit von nem Systemproperty.
So kennt deine GUI/Anwendungsschicht keine Details zum Backend.
 
G

Gast

Gast
Von DependencyInjection habe ich zuvor noch nie gehört. Von dem was ich nachgelesen habe, ist das doch eher für größere Projekte, denn um das umzusetzen wird ein Framework wie Spring oder PicoContainer benötigt.

Ist ein sauberes MVC Konzept nicht schon genug um das Ganze loose zu koppeln?
 

KSG9|sebastian

Top Contributor
Wieso brauchst du dafür Pico oder Spring?

Ne einfache Property-Datei genügt doch.

Code:
di.properties

de.test.IPersistenceManager=de.test.PersistenceManagerImpl

Code:
class DependencyResolver{
    private Properties props;
    public DepdendencyResolver(){
        props = new Properties();
        props.load(new File("di.properties"));
    }
    public <T> T resolve(Class<T> type){
        String value = props.getProperty(type.getName());
        Class<T> implType = Class.forName(value);
        return implType.newInstance();
    }
}

class ServiceLocator{
   private DependencyResolver resolver = new DependencyResolver();
   private IPersistenceManager persistenceManager;

   public IPersistenceManager getPersistenceManager(){
      if(persistenceManager == null){
         persistenceManager = resolver.resolve(IPersistenceManager.class);
      }
      return persistenceManager;
   }
}
 
G

Guest

Gast
Danke für das Beispiel!

Im Moment fühle ich mich so wie früher, als ich meine ersten Java Codezeilen geschrieben habe: Es fehlt der Überblick über das große Ganze.

Um etwas Licht ins Dunkle zu bringen hab ich mal versucht, es so graphisch darzustellen wie ich mir das im Moment vorstelle:
dependencyinjectionyq1.jpg

Ist das so korrekt?
 
G

Guest

Gast
Prima!

Was mir jetzt noch unklar ist, ist der Unterschied dazu:
controllerki6.jpg


Abgesehen davon, dass es verpönt ist einen monolitischen Controller zu bauen, der alle Objekte kennt. Im Grunde ist der Service Locator doch genau das Gleiche denn auch er kennt alle Objekte.
 

KSG9|sebastian

Top Contributor
Eigentlich wäre der Ablauf so:


GUI - Controller - ServiceLocator - DependencyResolver


Der Controller ist für die Logik zuständig. Der Controller holt sich über den ServicerLocator den IPersistenceManager.

Der ServiceLocator hat eine Instanz des DependencyResolvers und für jeden Manager (PersistenceManager..ABCManager...) eine Instanzvariable. Falls der gesuchte Manager null ist wird über den DepdendencyResolver versucht eine Instanz zu erzeugen.

Der IPersistenceManager ist wiederum dafür zuständig bestimmte Objekte zu laden, suchen, löschen oder updaten.

Die GUI sollte auch nicht direkt mit dem PersistenceManager kommunizieren. Der ServiceLocator ist auch kein Controller, er kapselt lediglich die DependencyInjection ab damit du im Controller nicht wissen muss was dort passiert.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
I Datenmodell für "Tags" Java Basics - Anfänger-Themen 6
P CSV Datei einlesen und damit ein Datenmodell befüllen Java Basics - Anfänger-Themen 2
N Datenmodell -> wie organisieren Java Basics - Anfänger-Themen 2
D 2 ArrayListen gleich sortieren bzw. eine Liste anhand einer anderen Sortieren Java Basics - Anfänger-Themen 6
X Multidimensionale Arraylisten Java Basics - Anfänger-Themen 1
S Verknüpfung von Arraylisten Java Basics - Anfänger-Themen 3
D Funktion zwei Arraylisten zu verleichen ob gleich funktioniert nicht Java Basics - Anfänger-Themen 26
D Arraylisten sortieren bitte um Hilfe Java Basics - Anfänger-Themen 4
feinperligekohlensaeure Arraylisten-Namen iterieren.. wie ? Java Basics - Anfänger-Themen 39
P Arraylisten nebeneinander ausgeben Java Basics - Anfänger-Themen 18
J .replace mit Arraylisten Java Basics - Anfänger-Themen 4
V Attribut aus aus jedem ArrayListen index auf Bildschirm ausgeben Java Basics - Anfänger-Themen 9
M Ein Array von Arraylisten Java Basics - Anfänger-Themen 4
F ArrayListen auf anderer Klasse implementieren Java Basics - Anfänger-Themen 4
Anfänger2011 2 kleine Fragen zu ArrayListen Java Basics - Anfänger-Themen 5
D Zwei ArrayListen<String> vergleichen. Java Basics - Anfänger-Themen 11
Joew0815 Zwei ArrayListen mit einander vergleichen Java Basics - Anfänger-Themen 33
U Übersicht trotz mehrdimensionaler Arraylisten Java Basics - Anfänger-Themen 17
K Arraylisten auslesen, kommt nur Quatsch raus Java Basics - Anfänger-Themen 15
B Zusammenfügen von zwei Arraylisten Java Basics - Anfänger-Themen 11
J Ausgabe von verschachtelten ArrayListen Java Basics - Anfänger-Themen 2
L 2 ArrayListen vergleichen Java Basics - Anfänger-Themen 2
G Geschachtelte ArrayListen Java Basics - Anfänger-Themen 27
O ArrayListen in der OOP Java Basics - Anfänger-Themen 7
A Macht es Sinn Arraylisten mit Gettern zu übergeben? Java Basics - Anfänger-Themen 19
J ArrayListen mit Name und Vater an JTree übergeben Java Basics - Anfänger-Themen 3
G Namen von ArrayListen dynamisch erzeugen Java Basics - Anfänger-Themen 4
G Mehrere Arraylisten in einer ArrayList speichern ? Java Basics - Anfänger-Themen 3
C ArrayListen in einer ArrayList der Grösse nach sortieren Java Basics - Anfänger-Themen 5
X bei ArrayListen in einer ArrayList werden alle gleich befüll Java Basics - Anfänger-Themen 6

Ähnliche Java Themen

Neue Themen


Oben