MichiLee
Vectoren und Hashtable in Java
- java
Hallo,
wenn ich nun sowas habe:
Vector[] columns = new Vector[4];
Also 4 Vector-Arrays
[0] -> Obj1, Obj2, Ob3
[1] -> Obj3, Obj4, Ob5
[2] -> Obj6, Obj7, Ob8
[3] -> Obj9, Obj10, Ob10
Nun nun tue ich immer ein Array in eine Hashtable
Hashtable<String, Vector<Object>> test = new Hashtable<String, Vector<Object>>();
test.put("Feld1",columns[1]);
test.put("Feld2",columns[2]);
test.put("Feld3",columns[3]);
test.put("Feld4",columns[4]);
1. Meine Frage nun, bei der Instanzierung der Hashtable oben brauche ich ja nicht Vector[]<Object> angeben, da ich ja kein Array hereintue, sondern nur einen Array-Teil eines Vector-Objekts ne?
2. Zwischen der Hastable und den einzelnen Vector-Arrays besteht aber nach dem einfügen keine Referenz zwischen Hashtable und zum Vector ne? (Sollte ich zum Beispiel Vector killen)
3. Auslesen kann ich die Hashtable dann ganz normal, indem ich den ersten Namen der Hashtable auslese und dann zum Namen des ersten Feldes das dazugehörige Vector-Objekt. Ich sollte dann vor allem nur wissen, dass im ersten Feld ein String ist und im zweiten ein Vector (kein Array)
Noch eine andere Frage.
Wenn ich zum Beispiel einen Vector habe den zum Beispiel folgendes geadded wurde:
4. Obj1, Obj2, Obj3, EigenesObj, Ob4, Obj5, Obj6, EigenesObj
Dann kann ich ja später beim Auslesen prüfen:
if(vector_.elementAt(i) instanceof EigenesObj){
Was wäre, wenn ich da nun anstatt ein EigenesObj ein String drinnen hätten: Obj1, Obj2, Obj3, "br", Obj4, Obj5, Obj6, "br"
Wie würde ich das dann in der If-Abfrage checken?
5. Meine letzte noch wirklich kurze Frage.
Wenn ich zu einem Vector zweimal das gleiche Objekten speichere: Obj1, Obj2, Obj3, EigenesObj, Obj3, Obj5, Obj6, EigenesObj
Das wäre dann keine Referenz ne, so dass bei Änderung von der Vector-Stelle(2) sich auch die (4) ändert?
Grüße
Hallo,
Erstmal: was hast Du denn genommen, dass Du so einen verplanten Beitrag geschrieben hast? :) Wobei ich die Vertauschung von Thema und Nick schon recht gut finde.
Also 4 Vector-Arrays
[0] -> Obj1, Obj2, Ob3
[1] -> Obj3, Obj4, Ob5
[2] -> Obj6, Obj7, Ob8
[3] -> Obj9, Obj10, Ob10
[...]
Hashtable<String, Vector<Object>> test = new Hashtable<String, Vector<Object>>();test.put("Feld1",columns[1]);
[...]
- Meine Frage nun, bei der Instanzierung der Hashtable oben brauche ich ja nicht Vector[]<Object> angeben, da ich ja kein Array hereintue, sondern nur einen Array-Teil eines Vector-Objekts ne?
Was Du genau in das Array packst, kann ich nicht sagen, weil Du das nicht in Quellcode dargestellt hast (zumindest nicht Java). Ich vermute aber, dass Du die kompletten Vector-Objekte reinpackst. Dann musst Du sie auch so typisieren, wie Du das getan hast.
- Zwischen der Hastable und den einzelnen Vector-Arrays besteht aber nach dem einfügen keine Referenz zwischen Hashtable und zum Vector ne? (Sollte ich zum Beispiel Vector killen)
Häh? Wenn Du meinst, ob die Hashtable etwas von dem Vector-Array weiß oder umgekehrt: nein, tut sie nicht.
- Auslesen kann ich die Hashtable dann ganz normal, indem ich den ersten Namen der Hashtable auslese und dann zum Namen des ersten Feldes das dazugehörige Vector-Objekt. Ich sollte dann vor allem nur wissen, dass im ersten Feld ein String ist und im zweiten ein Vector (kein Array)
Das weißt Du ja über die Typisierung mittels Generics. Das erste "Feld" ist übrigens der Key, das "zweite" der Value.
[...]
Was wäre, wenn ich da nun anstatt ein EigenesObj ein String drinnen hätten: Obj1, Obj2, Obj3, "br", Obj4, Obj5, Obj6, "br"
Wie würde ich das dann in der If-Abfrage checken?
if(xy instanceof String)
- Meine letzte noch wirklich kurze Frage.
Wenn ich zu einem Vector zweimal das gleiche Objekten speichere: Obj1, Obj2, Obj3, EigenesObj, Obj3, Obj5, Obj6, EigenesObj
Das wäre dann keine Referenz ne, so dass bei Änderung von der Vector-Stelle(2) sich auch die (4) ändert?
Ja, es würde sich das referenzierte Objekt ändern. Wenn die Referenzen auf die selbe Instanz zeigen, dann ändert sich für den Betrachter beides.
Schöne Grüße,
Peter
Hi,
Erstmal: was hast Du denn genommen, dass Du so einen verplanten Beitrag geschrieben hast? :) Wobei ich die Vertauschung von Thema und Nick schon recht gut finde.
sorry, war voll verplant. Hier mal der Code der in einer Methode ist, welches eine Hashtable zurückgibt:
Hashtable<String, Vector<Object>> hashes = new Hashtable<String, Vector<Object>>();
Vector<String> vect_1 = new Vector<String>(); //Hier sind 4 Strings drin
Vector[] vect_2 = new Vector[4];
//vect_2 wird dann mit Instanzvariablen/Attributen (Objekte) einer anderen Klasse gefüllt
[0] -> Obj1, Obj2, Ob3
[1] -> Obj3, Obj4, Ob5
[2] -> Obj6, Obj7, Ob8
[3] -> Obj9, Obj10, Ob10
while (i < vect_1.size()) {
hashes.put(vect_1.elementAt(i),vect_2[i]);
i++;
}
return hashed;
1. Wenn ich nun das Hash zurückgeben sollte, und später sich die Instanz bzw. das Attribut der anderen Klasse ändert sollte, ändern sich auch der Wert in hashes?
2. Wenn ich den Vector vect_2 nicht durch Objekte von einer anderen Klasse, sondern durch irgendwelche Objekte gefüllt hätte, die ich temporär/lokal in der Methode oben angelegt habe und das Hash zurückgebe, wie verhält sich das ganze an (Hoffentlich habe ich mich verständlich ausgedrückt)
Das lokale Objekt ist ja nach dem return dann weg, bzw. nicht mehr genutzt. Bzw. wenn zeitversetzt nochmals die Methode aufgerufen wird und dann nochmals das temporäre Objekt gebildet wird, um ein Hash zurückzugeben. Das hätte dann vermutlich keine Auswirkung auf das Hash, was davor zurückgegeben wurde oder?
Ah, ich denke wieder zu viel um die Ecken ;)
[...]
Was wäre, wenn ich da nun anstatt ein EigenesObj ein String drinnen hätten: Obj1, Obj2, Obj3, "br", Obj4, Obj5, Obj6, "br"
Wie würde ich das dann in der If-Abfrage checken?if(xy instanceof String)
Könnte ich in die IF-Abfrage auch gleich dann packen, ob er String ist, wenn ja, ob der Inhalt "br" ?
if (xy instanceof String && xy.equals("br"))
Sollte halt ein String sein, denn wenn es keine instanceof von String ist, sondern von was anders, dürfte .equals bei einer eigenen Klasse nicht gehen.
Grüße
Guten Morgen,
[...]
Hashtable<String, Vector<Object>> hashes = new Hashtable<String, Vector<Object>>();Vector<String> vect_1 = new Vector<String>(); //Hier sind 4 Strings drin
Vector[] vect_2 = new Vector[4];//vect_2 wird dann mit Instanzvariablen/Attributen (Objekte) einer anderen Klasse gefüllt
[0] -> Obj1, Obj2, Ob3
[1] -> Obj3, Obj4, Ob5
[2] -> Obj6, Obj7, Ob8
[3] -> Obj9, Obj10, Ob10while (i < vect_1.size()) {
hashes.put(vect_1.elementAt(i),vect_2[i]);
i++;
}return hashed;
- Wenn ich nun das Hash zurückgeben sollte, und später sich die Instanz bzw. das Attribut der anderen Klasse ändert sollte, ändern sich auch der Wert in hashes?
Scheinbar ist es noch zu früh, denn ich verstehe immer noch nicht, was da in Deinem Quellcode passiert. vect_2 ist ja definiert als Array von Vectoren, deshalb kannst Du dort nur Vector-Objekte ablegen. Du hast also am Ende der while-Schleife in der Hashtable die Strings aus vect_1 und den dazugehörigen (über den Index definiert) Vector aus vect_2. In dem einzelnen Vector in vect_2 stehen verschiedene Objekte (Obj1 - Obj10).
Die Hashtable zeigt intern nur auf Stellen im Speicher. Da liegt also z.B. der String mit dem Index 0 aus vect_1 an der Adresse 123. Es zeigen also vect_1 auf diese Adresse, und der erste Key in der Hashtable auch. Bei Strings hast Du aber den Fall, dass die immutable sind, die können sich also nicht ändern. Anders Deine Vector-Instanzen bzw. Obj1 - Obj10. Auch die haben irgendeine Adresse (z.B. 1000 - 1100 in 100er Schritten). Auf diese Adressen zeigen Deine Vectoren in dem Vector-Array, aber auch die Values in der Hashtable. Änderst Du jetzt eine dieser Instanzen (entweder durch einen Zugriff von der Hashtable aus oder von einem Vector aus, dann ändert sich das Objekt an der Speicherstelle. Und damit wird die Änderung sowohl für die Referenzen im Vector, als auch in der Hashtable gültig. Call by Reference ist hier das Stichwort.
- Wenn ich den Vector vect_2 nicht durch Objekte von einer anderen Klasse, sondern durch irgendwelche Objekte gefüllt hätte, die ich temporär/lokal in der Methode oben angelegt habe und das Hash zurückgebe, wie verhält sich das ganze an (Hoffentlich habe ich mich verständlich ausgedrückt)
Leider nein. Das Verhalten ist immer das oben beschriebene. Du hast Objekte an einer Stelle im Speicher und hältst Referenzen darauf. Wenn Du innerhalb einer Methode ein Objekt unter dem Namen "obj" erzeugst und in eine Hashtable ablegst und diese zurückgibst, dann gibt es nach dem Verlassen der Methode Dein "obj" nicht mehr. Aber es gibt noch die Referenz in der Hashtable und damit kann diese Instanz noch erreicht werden. Das ist auch der Grund, warum der Garbage Collector diese Instanz noch nicht abräumen kann: weil sie noch irgendwo referenziert wird.
[...]
if (xy instanceof String && xy.equals("br"))Sollte halt ein String sein, denn wenn es keine instanceof von String ist, sondern von was anders, dürfte .equals bei einer eigenen Klasse nicht gehen.
Dann reicht der Check auf null und der Aufruf der Methode equals. Diese ist für jedes Object definiert und prüft standardmäßig auf Instanzgleichheit (wieder die Adresse im Speicher). Wird sie von einer Unterklasse von Object überschrieben, dann kann hier inhaltliche Gleichheit geprüft werden. In fast jedem Fall wird aber innerhalb der Methode equals auch abgeprüft, ob die übergebene Instanz vom korrekten Typ ist. Denn ein Flugzeug kann fachlich nicht equal zu einem Auto sein.
Schöne Grüße,
Peter
Hi Peter,
super vielen Dank, dann habe ich das auch verstanden. Vielen vielen Dank.
Mich hatten die Hashtables etwas verwirrt, was die Referenzierung betrifft.
Dürfte ich dann gleich noch ein paar kleine Fragen zu Java loswerden.
Ich habe ein Interface Datasource. Dann habe ich zum Beispiel zwei Klassen DataDB und DataXML welches Datasource implementiert.
Nun habe ich eine Klasse DatasourceFactory welche entscheidet, mit was eine Datasource erzeugt wird (entweder DataDB oder DataXML) und gibt dann das erzeugte Datasource zurück.
Nun kann man von anderen Klassen von der DatasourceFactory ein getInstance() holen, wo ich dann eine Verbindung zur Datenbank (DataDB) oder einer XML-Datei (DataXML) habe.
Meine Fragen nun:
1. Ich könnte die DatasourceFactory ja statisch machen, mit statischen Klassenvariablen zum Beispiel für Parameter und dem Typ ob DB oder XML)
private static String typ = null;
privat static String parameter = null;
Dann könnte man in einer anderen Klasse die Methode init von DatasourceFactory aufrufen, welche die zwei Klassenvariablen füllt mit DatasourceFactory.TYP="DB"
Danach könnte man die Methoden statisch aufrufen. Normalerweise wird die DatasourceFactory auch nur von einer bestimmte Klasse aufgerufen. Könnte aber sein, dass andere Klassen das auch aufrufen.
Nun frage ich mich, wie sich das mit den Klassenvariablen verhält, wenn später eine andere Klasse darauf zugreift. Muss man irgendwie synchronisieren?
(Wenn das eine Applikation im Internetbetrieb wäre, wo mehrere Leute auf die Klassen/Klassenvariable zugreifen, wäre der Inhalt der Klassenvariablen ja egal, da es ja für jeden Benutzer, der auf die Klassenvariablen zugreift ja eh in einem eigenen Thread arbeitet oder? Oder überschreiben die sich irgendwie das hin und her?)
2. Für Commandos für DB(SQL) oder XML, die gebraucht werden, um irgendwelche Daten zu laden, schreibe ich dann ein eigenes Interface Commando, wo dann bestimmte Methoden vorgeschrieben werden, wie zum Beispiel public User getUser(int i)... Praktisch alle Daten, die die Applikation braucht werden hier vorgeschrieben. Eine CommandoDB implementiert dann diese Methode, um baut darauf ein Kommando zusammen. Die ganzen Models könnten dann das Interface ansprechen und sagen, dass sie einen User wollen, welches sie dann auch zurückkriegen.
Die CommandoDB nutzt dann evtl. die DatasourceFactory von oben um gleich das Kommando auch auszuführen oder gibt anstatt den User nur das Commando zurück, so dass das Model mit dem Commando auf DatasourceFactory zugreift.
Findet ihr diese Lösung akzeptabel? (Unser Lehrer schlug vor, anstatt oben eine DataDB zu haben, dass man das für jede Bereiche einzeln macht, bsp. DataUserDB, DataProjektDB, so dass die einzelnen Klassen dann jeweils einen User laden, editieren, löschen usw.
3. Meine letzte kleine Frage wäre, wenn ich zum Beispiel wie in Frage 1 in irgend einem Model von DatasourceFactory eine Datasource zurückkriege, was mit DataDB gebildet wurde, kann ich ja problemlos bsp. openSource() oder connect() aufrufen auf das Objekt, was von DataDB und DataXML implementiert wurde. Was wäre aber, wenn DataDB irgend eine spezielle Methode hätte, zum Beispiel isConnected(), was von Datasource nicht vorgeschrieben wurde, da es DataXML nicht braucht.
Ich hätte dann in DataDB die Methode isConnected() eingefügt, kann sie aber nich nutzen, da das Objekt so Datasource test = new DataDB() gebildet wurde und Datasource nicht die Methode isConnected hat?
Sowas geht dann allgemein nicht ne? Deshalb müsste ich mir von Anfang an überlegen, so dass es nicht so zu Überlappungen kommt ne?
Viele Grüße
Taner
Guten Morgen!
[...]
- Ich könnte die DatasourceFactory ja statisch machen, mit statischen Klassenvariablen zum Beispiel für Parameter und dem Typ ob DB oder XML)
private static String typ = null;
privat static String parameter = null;Dann könnte man in einer anderen Klasse die Methode init von DatasourceFactory aufrufen, welche die zwei Klassenvariablen füllt mit DatasourceFactory.TYP="DB"
[...]
Das ist eine schlechte Idee, deren Haken Du ja schon selbst erkannt hast. Jedesmal, wenn ein anderer Client die Klasse DatasourceFactory "initialisiert", dann überschreibt er damit für alle anderen Benutzer den zurückgelieferten Datentyp. Wenn also Client 1 mit "DB" anfängt, Client 2 aber dann "XML" verwendet, dann bekommt Client 1 das nächste Mal auch "XML".
(Wenn das eine Applikation im Internetbetrieb wäre, wo mehrere Leute auf die Klassen/Klassenvariable zugreifen, wäre der Inhalt der Klassenvariablen ja egal, da es ja für jeden Benutzer, der auf die Klassenvariablen zugreift ja eh in einem eigenen Thread arbeitet oder? Oder überschreiben die sich irgendwie das hin und her?)
Threads haben hier keinen Einfluss. Wichtig ist die VM. Statische Eigenschaften und Methoden werden pro VM initialisiert. Wie viele Threads in dieser VM arbeiten, ist dabei egal.
Ein sinnvoller Weg ist, das nicht über eine Eigenschaft der DatasourceFactory zu regeln, sondern beim Aufruf der Methode getDatasource() einen Parameter mitzugeben, welchen Typ man gerne hätte.
- [...]
Die CommandoDB nutzt dann evtl. die DatasourceFactory von oben um gleich das Kommando auch auszuführen oder gibt anstatt den User nur das Commando zurück, so dass das Model mit dem Commando auf DatasourceFactory zugreift.Findet ihr diese Lösung akzeptabel? (Unser Lehrer schlug vor, anstatt oben eine DataDB zu haben, dass man das für jede Bereiche einzeln macht, bsp. DataUserDB, DataProjektDB, so dass die einzelnen Klassen dann jeweils einen User laden, editieren, löschen usw.
Das kommt auf den Umfang der Methoden an. Sind es insgesamt nur 5 oder 10 Abfragen, dann kann man das schon in einem Interface abbilden. Aber 10 ist meiner Erfahrung nach schon die absolute Höchstgrenze. Ich bin ein Freund von kleinen und spezialisierten Klassen.
- [...]
Ich hätte dann in DataDB die Methode isConnected() eingefügt, kann sie aber nich nutzen, da das Objekt so Datasource test = new DataDB() gebildet wurde und Datasource nicht die Methode isConnected hat?
Sowas geht dann allgemein nicht ne? Deshalb müsste ich mir von Anfang an überlegen, so dass es nicht so zu Überlappungen kommt ne?
Das geht nur, wenn Du weißt, dass das Ergebnisobjekt von einem bestimmten Typ ist, und Du auf diesen (speziellen) Typ castest. Allerdings sollte das in einem gut entworfenen Modell nicht nötig sein. Das ist ja das schöne an fachlichen Interfaces, dass man sich eben nicht mehr darum kümmert, welche konkrete Implementierung man im Hintergrund serviert bekommt. Versuche, Deine Anwendung so zu schreiben, dass Du keine solchen Hintertürchen brauchst. Die Datasource-Implementierung selbst sollte sich um solche Dinge wie Connection-Management kümmern. Wenn hier ein Fehler auftritt, kannst Du ja eine fachliche Exception werfen, die Du auch im Interface deklarierst. So hast Du immer die Gewissheit, dass auf solche technischen Schwierigkeiten adäquat reagiert werden kann, ohne dass man gleich die Implementierung kennen muss.
Insgesamt gefällt mir Deine Herangehensweise sehr gut. Deine Gedanken machen Sinn und Du beschäftigst Dich intensiv mit dem Thema. Dein konkretes Modell ist ein wichtiges Konstrukt in der objektorientierten Softwareentwicklung und ein weit verbreitetes Design Pattern (eigentlich zwei: Factory und Data Access Object). Mach weiter so!
Schöne Grüße,
Peter
Hi Peter,
vielen vielen Dank, du machst mir echt Mut und gibst Freude, mich noch mehr mit allem zu Beschäftigen. (Gut zu wissen, dass eine Klassenvariable für die ganze VM gilt. Also praktisch dann für alle. Muss mir dann noch anschauen, wo dann Synchronisation eingesetzt wird, bzw. wo man das braucht, da ich das schon oft sehe und mir denke, warum man da jetzt unbedingt synchronisieren muss)
Das einzige Problem, was ich derzeit noch habe, sind die Exceptions, wo ich in diesem Thread die Anfrage gestartet habe:
http://forum.de.selfhtml.org/?t=196746&m=1318614
Ich habe ja eine DataSourceFactory, mit Inteface DataSource und DatasourceSQL und das gleiche mit QueryFactory mit Interface Query und QuerySQL.
1. Mein Controller ruft ein UserModel auf, welches dann zum Beispiel ein User laden tut, indem das UserModel eine Query erzeugt, das Query benutzt dann Datasource. Wie auch immer.
Ich frage mich nun, wenn ein Fehler beim UserModel ankommt, wie er es handhaben sollte. Laut Sven sollte man ja nicht alle Fehler bis zum Controller weiterreichen, (Bsp. mysql-Treiber konnte nicht gefunden usw.)
Praktisch, wie weit ich immer einen Fehler weiterreichen soll.
2. Meine noch derzeitige Überlegung ist, wenn der Controller nach einem Login einen UserModel aufruft und ihm sagt: loadUserAfterLogin(userid, password)
Dann gibt das UserModel ein Objekt "User" zurück. Der Controller schaut, ob er ein "User" zurückbekommen hat, wenn ja, war der Loginversuch erfolgreich, ansonsten könnte der Controller sagen: "Ich habe kein User bekommen, ich schaue mal, ob es die UserID, bzw. den Usernamen überhaupt gibt, um die Fehlermeldung zu sagen, dass nur das Passwort falsch ist)
Dann wird erneut das UserModel aufgerufen, was mir dann ein boolean zurückgibt, ob es den User gibt.
Also habe ich zweimal das UserModel aufgerufen. Oder, ob ich vieles gleich vom Model erledigen lassen sollte, wenn er kein User findet, dass er dann selebr von sich aus prüft, dass es den Benutzer nicht gibt usw.
Ich glaube, das erstere wäre wohl besser :-)
Danach schaue ich mir die GUI's an, wie ich das realisiere und vom Controller aus einen persönlichen Bereich eines Users erstelle, was ich von was ableite, wie ich dann Änderungen vornehme vom Controller oder ob ich gleich eine neue Maske erstelle usw. usw, aber da bin ich in diesem Forum ja falsch. Da ist noch viel Arbeit. Ich denke, dass die Logik an sich mit dme Controller eigentlich schon gut steht, auch wenn ich nicht alle Richtlinien und Strategien/Prinzipien einhalten kann, bzw. Geschweige denn davon gehört habe. Gibt es eigentlich irgendwelche Richtlinien, ob man bestimmte Methoden statisch programmiert oder indem man erst ein Objekt bilden muss?)
Zu viele Fragen irgendwie, ich hoffe, dass es auch die letzten waren für die nächsten 2 Wochen ;)
Grüße
Servus,
[...]
Ich frage mich nun, wenn ein Fehler beim UserModel ankommt, wie er es handhaben sollte. Laut Sven sollte man ja nicht alle Fehler bis zum Controller weiterreichen, (Bsp. mysql-Treiber konnte nicht gefunden usw.)
Da gibt es sehr viele verschiedene Herangehensweisen. Ich handhabe es so: handelt es sich um eine Exception, deren Auswirkung ich an Ort und Stelle beheben kann (z.B. Konfiguration nicht gefunden aber Defaultwerte vorhanden), dann fange ich die Exception und mache im catch-Block etwas sinnvolles. Ansonsten definiere ich für jede Schicht ein entsprechendes Set an Exceptions (das dürften die Helfer im anderen Thread auch schon genannt haben). Diese Exceptions sind für die jeweilige Schicht immer passend. So gibt mir die Serviceschicht keine SQL-Exceptions zurück, sondern z.B. ein UserNotFoundException. In den jeweils darüber liegenden Schichten höre ich auf diese Exceptions und arbeite nach der o.a. Regel: kann ich was sinnvolles tun, tu ich es, ansonsten schmeiß ich eine Schicht-spezifische und sinnvolle Exception (z.B. aus einer SQL-Exception des Persistence-Layer wird eine entsprechende fachliche Exception (z.B. UserNotFoundException) im Service-Layer). Ganz oben in der GUI muss ich dann aus den entsprechenden Service-Exceptions Fehlermeldungen bauen. Wobei hier in vielen Fällen der Benutzer keinen genauen Grund genannt bekommt, sondern einfach einen "Technischer Fehler" serviert bekommt. Die Details interessieren nur den Admin und die Entwicklung (und die lesen das Log).
[...]
Also habe ich zweimal das UserModel aufgerufen. Oder, ob ich vieles gleich vom Model erledigen lassen sollte, wenn er kein User findet, dass er dann selebr von sich aus prüft, dass es den Benutzer nicht gibt usw.
Ich glaube, das erstere wäre wohl besser :-)
Ich bin der Meinung, dass jeder das machen sollte, was er am besten kann. Wenn das UserModel für die Ermittlung von Usern zuständig ist, dann lass es das auch tun. Hier kann man in meinen Augen keinen allgemein gültigen Rat geben. Mach es erst mal auf eine Art und schau den Code in einem halben Jahr wieder an. Wenn er Dir gefällt: gut. Wenn nicht, dann mach es dann anders. Refaktorisiert wird eh immer. :)
Viel Erfolg weiterhin!
Peter