Frage zur Anwendung des MVC-Konzept

Eldorado

Bekanntes Mitglied
Hi,
ich habe das mvc-Tutorial von sun durchgearbeitet und zu folgender Methode eine Frage:
Java:
    protected void setModelProperty(String propertyName, Object newValue) {

        for (AbstractModel model : registeredModels) {
            try {

                Method method = model.getClass().
                        getMethod("set" + propertyName, new Class[]{
                            newValue.getClass()
                        });
                method.invoke(model, newValue);

            } catch (Exception ex) {
                //  Handle exception
            }
        }
    }
Hier werden alle model durchgegangen und die Methode "set" + property aufgerufen. Es besteht doch aber ein Problem, wenn man zwei Model drin hat, die beide die Methode z.Bsp. setName(String name); haben, jedoch diese beiden model nichts miteinander zu tun haben und so auch die Methoden etwas anderes machen. Wie kann man diese Problem umgehen, wenn man diese Architektur benutzen möchte?
 

Marco13

Top Contributor
Hmja... man könnte darüber philosophieren, wie allgemein anwendbar und praxistauglich dieses Modell wirklich ist. Im konkreten Fall könnte man noch die Klasse des Zielmodells übergeben...
Code:
class Auto implements Model { public void setName(String s) { ... } }
class Mensch implements Model { public void setName(String s) { ... } }

...
setModelProperty("Name", "Ferrari", Auto.class);
und in der Methode dann abfragen, ob das jeweilige Objekt von einer Klasse ist, die zur übergebenen passt. Ob das "schön" ist? ???:L Hm. :bahnhof:
 

Eldorado

Bekanntes Mitglied
Hmja... man könnte darüber philosophieren, wie allgemein anwendbar und praxistauglich dieses Modell wirklich ist.
Ich hatte auch schon das Gefühl, dass das doch alles relativ umständlich ist. Ich möchte aber natürlich ein Konzept, dass die Daten und die Darstellung gut von einander abkoppelt, um später keine Probleme mit der Erweiterung bzw. der Veränderung zu haben. Für andere Umsetzungen bin ich voll und ganz offen :toll:
 

Marco13

Top Contributor
Naja, "umständlich" ist es eigentlich nicht, genaugenommen sogar sehr einfach. NOCH einfacher geht's eigentlich nur mit sowas wie swirrel - Project Hosting on Google Code (von 'Landei' hier aus dem Forum).

Aber genau der Link, den du im ersten Beitrag gepostet hattest, hatte mich damals zu der Frage veranlasst: http://www.java-forum.org/allgemein...rwendet-man-propertychangedevents-eigene.html ... Ich weiß nicht, ob das nicht nur ein Beispiel sein sollte, um zu verdeutlichen, welche Idee grundsätzlich hinter MVC steckt. Irgendwie kann ich mir kaum vorstellen, dass man in einer "echten" Anwendung mit 100 Modellklassen und 1000 "Properties" alles über String-Identifier und 'Object's lösen sollte.....
 

Michael...

Top Contributor
Wenn ich mich mal zwischen rein reden darf ;-)

Ich mach mir immer vorher Gedanken wie Mein Model grundsätzlich aussehen soll und definiere dem entsprechend ein Interface, AbstractModel oder eine konkrete Klasse, die der Controller kennt.

Eine grössere Flexibiliät/Unabhängikeit des Controllers vom Model, kann ich bei der Vorgehensweise nicht wirklich erkennen. Wo ist da der Unterschied, ob der Controller die Implementierung/Schnittstelle des Models und somit seiner Methoden kennt oder nur die Methodennamen? In beiden Fällen muss, wenn das Model erweitert wird u.U. der Controller angepasst werden.

In dem Beispiel ist es sogar so, dass das Model den Controller (DefaultController) kennt, um auf dessen statische Variablen zu zugreifen. Das widerspricht ganz meiner Erwartung an ein MVC.
 

Marco13

Top Contributor
Ich persönlich tendiere eher dazu, spezifische Event/Listener-Klassen für spezifische Modellklassen zu schreiben. Wenn man ein größeres Projekt von vornherein plant (und nicht als jemand dient, der MVC in ein Projekt einbauen darf, das vorher 6 Jahre lang ohne solche Strukturen entwickelt wurde ;) ) dann würde sich mir die Frage aber wieder stellen: Wenn man 10 Modellklassen hat, die alle ein paar addXXX/removeXXX-Methoden haben, und überall "strukturell gleiche" Listener, Events und AbstractModel-Klassen auftreten wirkt das so repititiv (und verstößt eigentlich gegen das DRY-Prinzip). Generics können da in gewissen Grenzen helfen, aber sind nicht die Universalwaffe. Auch im verlinkten Thread kam ja keine definitive Antwort (wie auch...) - man muss das wohl von Fall zu Fall entscheiden. Wenn man wirklich ein Bean/Pojo hat, kann der PropertyChangeListener vielleicht sinnvoll sein, aber mir gefallen (subjektiv) die spezifischen Klassen besser.
 
M

maki

Gast
Ich finde das bei JFace Databinding sehr gut gelöst, die Modellklassen müssen nur konform zum JavaBeans PropertyChangeSupport sein, bietet sich für MVP an.
Wobei, es geht auch ohne PropertyChangeSupport.
 

Eldorado

Bekanntes Mitglied
@Michael: freue mich, wenn jemand reinredet :D
Zu Thema Bohnen: da ich Hibernate für den Datenbankzugriff benutze, habe ich zwangsläufig Beans. In diesem Fall würden sich also PropertyChangeListener eignen. Wäre der Aufbau dann so, dass ich im Controller alle Bohnen in einer Liste ablege und jeweils einen Listener adde. Wenn dieser Anschlägt das event an die gui weitergebe und diese sich dann udated?
 

Marco13

Top Contributor
Mit Hibernate kenne ich mich nicht aus, und so remote und ohne genaue Kenntnis des Zusammenhangs zu beurteilen, ob ein Aufbau "sinnvoll" ist, ist immer schwierig. Es klingt erstmal(!) als würde da ziemlich viel vermischt, je nachdem worum es genau geht könnte man vielleicht versuchen, die Dinge irgendwie zu gruppieren... Vielleicht sowas wie
Code:
private List<Customer> customers = ...
private List<Product> products = ...

private void init()
{
    for (Customer c : db.getCustomers()) 
    {
        customers.add(c);
        c.addPropertyChangeListener(theListenerThatPassesEventsToCustomerView);
    }
    for (Product p : db.getProducts()) 
    {
        products.add(p);
        p.addPropertyChangeListener(theListenerThatPassesEventsToProductView);
    }
}
anstatt wirklich ALLES als "irgendeine bean" mit "irgendeinem PropertyChangeListener" in EINE Liste zu packen. Das ist KEIN Vorschlag, nur ein in-den-Raum-stellen der Möglichkeit (auf Basis dessen, was du bisher geschrieben hast). Ob das "sinnvoll" ist, kannst eigentlich nur du entscheiden ;)
(Als Beispiel: Wenn du irgendeine Super-Generische View hättest, die irgendeine Bean bekommt, und stupide mir reflection alle set-Methoden durchgeht und eine Ansicht erstellt mit
| property0NameLabel | property0ValueTextField |
| property1NameLabel | property1ValueTextField |
...
dann könnte man auch alles vereinheitlichen - aber vermutlich hast du das nicht, und vermutlich(!) würde es unübersichtlich werden, wenn man alles in einen Topf wirft...)
 

Eldorado

Bekanntes Mitglied
Ok, danke. Ich glaube ich werde mich mal dransetzen und was zeichnen, um einerseits den Aufbau nochmal zu überdenken und ihn euch verständlich zu machen.
 

Eldorado

Bekanntes Mitglied
OK, ich versuch es doch mit beschreiben, da ich beim Zeichnen so ne Niete bin^^
--------------------------------------
Das Haupt-Model, das Zugriff auf die UnterModel und somit deren Daten bietet. Es reicht PropertyChanges von den Unter-Models an die Listener des Haupt-Models weiter und feuert selbst welche, wenn neue Daten hinzukommen.
Java:
public class MainModel implements PropertyChangeListener{

    private PropertyChangeSupport propertyChangeSupport;
    private ArrayList<User> userList;
    private ArrayList<Product> productList;
    //etc.

    public MainModel() {
        propertyChangeSupport = new PropertyChangeSupport(this);
        userList = new ArrayList<User>();
        productList = new ArrayList<Product>();
        //Stelle Datenbankverbindung her
        //Lese Daten aus der Datenbank aus
    }

    public User getUser(int userId) {
        //User aus der Datenbank lesen und zurückgeben
    }

    public User addUser(User user) {
        //User in die Datenbank schreiben
        userList.add(user);
        user.addPropertyChangeListener(this);//Untermodel haben auch PropertyChangeSupport
        propertyChangeSupport.firePropertyChange(Data.USER.getIndetifier(), null, user);
    }

    //für Produkt etc. das selbe

    public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener){
        propertyChangeSupport.addPropertyChangeListener(propertyChangeListener);
    }

    public void removePropertyChangeListener(PropertyChangeListener propertyChangeListener){
        propertyChangeSupport.removePropertyChangeListener(propertyChangeListener);
    }

    //Listener für events aus den dahinter liegenden Modeln werden "weitergegeben"
    public void propertyChange(PropertyChangeEvent evt) {
        propertyChangeSupport.firePropertyChange(evt);
    }
}

Das Enum Data beinhaltet alle Möglichen Daten:
Java:
ppublic enum Data {

    USER("user"),
    USER_ID("userId"),
    USER_NAME("userName"),
    USER_CATEGORY("userCategory"),
    USER_STATE("userState"),
    
    USERCATGEORY("usercategory"),
    USERCATEGORY_ID("usercategoryId"),
    USERCATEGORY_NAME("usercategoryName"),

    PRODUCT("product"),
    PRODUCT_ID("productId"),
    PRODUCT_NAME("productName"),
    PRODUCT_CATEGORY("productCaegory"),
    PRODUCT_STATE("productState"),
    PRODUCT_RETAIL_PRICE("productRetailPrice"),
    PRODUCT_PURCHASE("productPurchase"),

    PRODUCTCATEGORY("productcategory"),
    PRODUCTCATEGORY_ID("productcategoryId"),
    PRODUCTCATEGORY_NAME("productcategoryName"),

    SALE("sale"),
    SALE_ID("saleId"),
    SALE_DATE("saleDate"),
    SALE_USER("saleUser"),
    SALE_PRODUCT("saleProduct"),
    SALE_AMOUNT("saleAmount"),
    SALE_DATE_PRICE("saleDatePrice"),

    SETTLEMENT("settlement"),
    SETTLEMENT_ID("settlementId"),
    SETTLEMT_DATE("settlementDate"),
    SETTLEMENT_USER("settlementUser"),
    SETTLEMENT_MONEY("settlementMoney"),

    ORDER("order"),
    ORDER_ID("orderId"),
    ORDER_DATE("orderDate"),
    ORDER_PRODUCT("orderProduct"),
    ORDER_AMOUNT("orderAmount"),
    ORDER_PRICE("orderPrice");

    private Data(String indentifier) {
    }

    String getIndetifier(){
        return "";
    }
}

Und zu guter letzt die Gui:
Java:
public class Gui implements PropertyChangeListener{

    public Gui(MainModel model) {
        model.addPropertyChangeListener(this);
    }

    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().equals(Data.USER.getIndetifier())) {
            //update
        }
        //...
    }

    public void addButtonDoSomethingListener(){
        //entweder cih mache einen Controller der tausende von Listener für 
        //alle Gui-Komponenten setzt oder ich behanlde die events in der 
        //gui und habe so halt viele kleine controller
    }
}

So wäre nett, wenn ihr kritische Kommentare abgebt und reinredet :D. Vielen Danke Leute!
 

Marco13

Top Contributor
Wie oben schon angedeutet würde ich tendenziell versuchen, die einzelnen Dinge zu trennen: Also Listener für User, und Listener für Produkte, und Listener für das MainModel. Ich könnte mir vorstellen, dass das die ganze Sache flexibler macht. Wie die Abfragen nach den Identifiern (ohne n) in der GUI dann weiter aussehen würden, wäre wohl ganz spannend, aber dazu würde vermutlich (zu) viel GUI-Code gehören.

Aber als GANZ grobes Beispiel: Wenn man aus dem GUI z.B. den SALE-Teil rausnehmen oder einen anderen hinzufügen will, oder das Verhalten sich etwas ändern soll, müßte relativ viel geändert werden - im speziellen das Data-enum und die (vermutlich schon sehr lange und unübersichtliche) propertyChange-Methode im GUI.

Wie es jetzt ist, ist es zwar nicht das, was mal als "Gegenbeispiel für Lose Kopplung" bezeichnen würde (da nicht wirklich "gekoppelt", sondern eher Zusammengefasst wird), aber bei mir bleibt da doch das (subjektive!) Gefühl, dass vieles vermischt und verdengelt ist, und damit evtl. später Änderungen aufwändiger werden könnten. Ob das wirklich so ist, ist im Voraus schwer zu sagen. (Und vielleicht ist das so ja auch die ultimative Standard-Vorgehensweise, wenn man Beans aus einer Hibernate-DB holt? :bahnhof: ). Aber vielleicht hat ja noch jemand anderes Kommentare dazu, damit du nicht nur mein unfundiertes Gelaber lesen mußt :D
 

Eldorado

Bekanntes Mitglied
Ich bin grad dabei mir ein neues Konzept auszudenken(Ich bin dir dafür dankbar Marco, dass du mir Probleme aufzeigst und mich dadurch zwingst mir Gedanken zu machen. Da ist es mir egal, ob ich "unfundiertes Gelaber lesen muss":)).
Problem: Ich habe die Datenbankeinträge durch Hibernate ja als Objekte in meinem Programm. Werden jetzt die Daten eine dieser Objekte geändert, muss es wieder mit der Datenbank synchronisiert werden.
Möglich Lösung: Ich registriere im Haupt-Model einen DataChangedListener(Meinen eigenen Listener). Wenn dann event auftritt würde ich eine Datenbankverbindung herstellen und das Objekt synchronisieren.
Frage: Ist das MVC-Konzeptionell in Ordnung?
 
G

Gast2

Gast
Also ich finde das JFace Databinding auch Klasse...

Ich würde den Aufbau so gestalten:
Auf dem Client würde ich GUI/Controller/Model abtrennen.
Auf derm Server hast dan Services für das Transaktions Handling und BU Logik verantwortlich sind. Die greifen auf DAO Klassen zu, um deine Hibernate Pojos zu speichern und löschen usw.

Der Controller(oder Model) ruft die Remote Service vom Server auf und befüllt und validiert deine Models auf dem Client. Eventuell kannst deine Hibernate Pojos auch noch in ModelObjects wrappen damit du dort den ProprtyChangeSupport reinmachen kannst.

Um die Models und ModelObjects zu generieren höre ich immer wieder dass EMF schon viel mitbringt und viel Arbeit abnimmt(PropertySupport, Validierung usw.), hab mich leider selber noch nicht intensiv damit beschäftigt, wird aber bei nächster Gelegenheit nachgeholt ;)...
 

Eldorado

Bekanntes Mitglied
Ähm, entweder verstehst du mich falsch oder ich verstehe nicht was du meinst :D
Ich habe keinen "Server", sondern nur einen Client, der über Hibernate auf eine MySQL-Datenbank(diese liegt logischerweise auf einem Server)(oder jede andere unterstützte Datenbank) zugreift und mit dem Daten arbeitet. Es geht mir zurzeit wirklich nur darum:
Auf dem Client würde ich GUI/Controller/Model abtrennen.
Aber trotzdem Danke!
 
G

Gast2

Gast
Was an der Schichten Trennung nichts ändern würde außer dass du kein Remote Zugriff hast...

MVC - Service - DAO - Hibernate POJOs
 

Eldorado

Bekanntes Mitglied
Ich poste euch mal meinen aktuellen Stand. Wenn ihr Lust habt, könnt ihr gerne euren Kommentar zu abgeben. Ich will auch aber auch nicht zuviel Arbeit machen hier ständig meine Ansätze durchzuschauen. Auf jeden Fall schon mal Danke an alle :toll:. Zum Thema JFace: Werde ich mir mal bei Gelegenheit genauer betrachten.

Ich habe jetzt eine generische DAO-Klasse geschrieben, die sich um die Datenbankkommunikation und das feuern von Events kümmert:
Java:
public class GenericDAO<T extends IndexableData> {

    private Session session;
    private Class<T> entity;
    private ArrayList<DataChangedListener> listeners;

    public GenericDAO(Session session) {
        this.session = session;
        this.entity = (Class<T>) ((ParameterizedType) getClass()
                                .getGenericSuperclass()).getActualTypeArguments()[0];
        listeners = new ArrayList<DataChangedListener>();
    }

    protected Session getSession() {
        if (session != null) {
            return session;
        }
        throw new IllegalStateException("Session has not been set.");
    }

    public List<T> getAll() {
        return getSession().createCriteria(entity).list();
    }

    public T loadById(int id) throws HibernateException{
        return (T) getSession().load(entity, id);
    }

    public void save(T entity) {
        getSession().save(entity);
        fireDataCahngedEvent(new DataChangeEvent(entity, Events.ADD));
    }

    public void update(T entity){
         getSession().update(entity);
        fireDataCahngedEvent(new DataChangeEvent(entity, Events.UDPATE));
    }

    public void delete(T entity) {
        getSession().delete(entity);
        fireDataCahngedEvent(new DataChangeEvent(entity, Events.REMOVE));
    }

    public void addDataChangedListener(DataChangedListener listener){
        listeners.add(listener);
    }

    public void removeDataChangedListener(DataChangedListener listener){
        listeners.remove(listener);
    }

    private void fireDataCahngedEvent(DataChangeEvent event){
        for (DataChangedListener dataChangedListener : listeners) {
            dataChangedListener.dataChanged(event);
        }
    }
}
IndexableData ist ein einfaches Interface, das getter und setter für eine id bereitstellt. Die Gui(und der Controller) holen sich die DAOs aus einer DaoFactory. Dies ist auch die einzige Klasse die für ein neues Daten-POJO angepasst werden muss:
Java:
public class DAOFactory {

    public static final int USER = 0;
    public static final int USER_CATEGORY = 1;
    public static final int PRODUCT = 2;
    public static final int PRODUCT_CATEGORY = 3;
    public static final int SALE = 4;
    public static final int SETTLEMENT = 5;
    public static final int ORDER = 6;
    private static GenericDAO[] dAOs;

    public DAOFactory() {
        DatabaseAdapter da = new DatabaseAdapter(null);
        dAOs = new GenericDAO[7];
        dAOs[0] = new GenericDAO<User>(da.getSession());
        dAOs[1] = new GenericDAO<UserCategory>(da.getSession());
        dAOs[2] = new GenericDAO<Product>(da.getSession());
        dAOs[3] = new GenericDAO<ProductCategory>(da.getSession());
        dAOs[4] = new GenericDAO<Sale>(da.getSession());
        dAOs[5] = new GenericDAO<Settlement>(da.getSession());
        dAOs[6] = new GenericDAO<Order>(da.getSession());
    }

    public GenericDAO getDAO(int key) {
        return dAOs[key];
    }
}

Wird ein neues Element vom Controller hinzugefügt oder verändert wird das entsprechende event gefeuert. Die Gui muss dann nur noch zwischen add, update, delete switchen(Enum).
Java:
public class DataChangeEvent extends EventObject {

    private Events eventType;

    public DataChangeEvent(IndexableData source, Events eventType) {
        super(source);
    }

    public Events getEventType() {
        return eventType;
    }

    public int getId(){
        IndexableData temp =  (IndexableData)getSource();
        return temp.getId();
    }
}
Java:
public interface DataChangedListener extends EventListener {

     public void dataChanged(DataChangeEvent event);

}

Da jeder "Datentyp" seinen eigenen Listener hat fällt das switchen zwischen den verschiedenen "Datentypen" im Listener weg und so ist eine Anpassung auch nicht aufwendig. ich hoffe, dass ich jetzt auf einem besseren weg bin. Wenn nicht, dürft ich mich auch gerne wieder dazu veranlassen den Papierkorb aufzumachen ;). Ich habe damit kein Problem, da man ja bekanntlich aus Fehlern lernt :)
 
G

Gast2

Gast
Also ich würde sowas in keiner Datenbank Zugriff Klasse machen... Sonst musst du die ja irgendwo regisitieren und ein DAO ist KEIN Model... Darum würde ich es nicht dort ansiedeln wenn ich heut daheim bin kann ich ja ein kleines Bsp. wie ich es machen würde...

Aber warte mal was maki dazu sagt ich glaub er hat da mehr Erfahung als ich ;)
 
M

maki

Gast
Aber warte mal was maki dazu sagt ich glaub er hat da mehr Erfahung als ich
Naja.. Hab ehrlich gesagt weder mit Swing noch mit SWT/JFace im zusammenhang mit DBs gearbeitet wo PropertyChange direkt aus dem Model gefeuert wurden, hatten immer ein eigenes Model für die View auf Rich Clients, welches entweder das "echte" Model gewrapped hatte oder dazu konvertiert wurde, Fowler nennt das Presentation Model, hab hier im Forum letztens den Begriff "Model View Adapter" von Ebenius gehört.

Muss SirWayne zustimmen, würde das nicht alles ins DAO packen (würde es noch nicht mal in richtige Domänenmodell packen).

Wenn ein Datensatz/Entity in Bearbeitung ist, wird dieser gelockt(!), damit gibt es keine parallelen Änderungen, wäre auch sehr schlecht für die Konsistenz ;)
Dazu gibt es 2 grundlegende Ansatze, Optimistic und Pessemistic locking (auch da hat fowler einen Artikel zu ;)), ersteres wird durch JPA/Hibernate/EclipseLink etc. direkt unterstützt (@Version Annotation) und üfrht dazu, das erst beim Speichern festgestellt (per Exception) wird ob man eine "Stale" Entity hatte.
Bei letzterem wird er Datensatz direkt in der DB gelockt (zB. select for update), je nach DB unterscheidet sich das schon mal ...
Dann gibt es noch die "Offline" Abwandlungen dazu, d.h. die Anwendung selber verwaltete das Pessemistic bzw. Optimistic Locking und ist dadurch unabhängig von der DB.

PropertyChangeSupport haben wir ausschliesslich genutzt, um das (Presentation-)Model mit der View zu synchronisieren bzw. umgekehrt.
 

Eldorado

Bekanntes Mitglied
Verbindung von dem Presentation Model und der view ist klar. Aber wie verbindet man das Model mit dem Presentation Model ohne den ganzen Code doppelt und dreifach zu schreiben. Du hast gesagt:
das "echte" Model gewrapped hatte oder dazu konvertiert wurde
Die Verbindung von den POJOS - DAO - Presentation Model ist mir noch nicht so ganz klar. Könntest du da vielleicht noch ein bisschen Licht ins dunkle bringen. :)
 
M

maki

Gast
Versuche es mal ;)

Der generelle Ablauf sieht ungefähr so aus:
View -> Service -> DAO -> DB

DAO hat rein gar nix mit dem PresentationModel zu tun, das DAO gibt (u.a.) eine Entity zurück, dieses kann ein POJO sein.
Die View kennt das PresentationModel, dieses ist anders als die eigentliche Entität, hat zB. spezielle Eigenschaften die nur für diese Views gebraucht werden (zB. PropertyChangeSupport, IAdabtable etc. pp.).
In einfachen Fällen reicht ein Wrapper die von der View um die Entities "gestülpt" werden, in schwierigeren braucht es TransferObjekte, die vom Service zurückgegeben werden und von der View in das PresentationModel konvertiert werden (und natürlich zurück).

Kandidaten für Redundanz sind zB. Validierung, wobei die View meist nur eifnache Validierung durchführen kann (Feld darf nicht leer sein bzw muss eine Zahl enthalten), komplexe Sachen werden dann "hinter" dem Service validiert.
 

Eldorado

Bekanntes Mitglied
Verstehe ich das Richtig: Es gibt 1 PresentationModel, das die View kennt um mit dem die View kommuniziert. So jetzt habe ich ganz viele Pojos, die ich über das Dao bekomme und jetzt ...?
Ich verstehe nicht was mit wrappen gemeint ist, bzw wie das umgesetzt wird...
Abermals danke für deine Hilfe.
 
M

maki

Gast
Verstehe ich das Richtig: Es gibt 1 PresentationModel, das die View kennt um mit dem die View kommuniziert. So jetzt habe ich ganz viele Pojos, die ich über das Dao bekomme und jetzt ...?
Nicht nur ein einziges, sondern je nach View und wie es gebraucht wird.

Ich verstehe nicht was mit wrappen gemeint ist, bzw wie das umgesetzt wird...
Das Adapter Muster, für die View braucht dein PresentationModel bestimmte Dinge, die deswegen nicht zur Entity gehören, weil diese sonst Abhängigkeiten zur View Techn. hätte.
Du hast jetzt zB. Abhängkeiten zur View techn. in deinem DAO & und deinen POJOs.
Entkoppeln bedeutet eben Aufwand, dafür schafft es klarheit :)
 

Eldorado

Bekanntes Mitglied
maki, ich habe eine Idee wie wir vielleicht schneller fertig werden: Das Forum hat doch einen TeamSpeak 2 Server. Wenn du Lust hättest könnte wir uns ja da miteinander unterhalten?
 

Eldorado

Bekanntes Mitglied
Zurzeit sind doch Pojos und DAO völlig unabhängig zur View. Du kannst jede View daraufpacken, diese würde sich ihre Daten holen und sich für Änderungen registrieren. Natürlich ist die View abhängig von einem Model das das Interface implementiert hat, aber das ist doch denke ich normal...
Das PresentationModel ist aber immer anhängig zur View(logischerweise). Kannst du vielleicht nur mal ganz kurz ein Beispiel geben, wie ich meine Entity in PresentationModel wrappe? Sorry, das ich wahrscheinlich grade total schwer von Begriff bin -.-
 
M

maki

Gast
Du schreibst einfach eine Klasse, die eine Entity aufnimmt (zb. per Konstruktor), und dann Aufrufe auf den Wrapper an die Entity delegiert (get.., set...), da kannst du zB. auch deine Events abfeuern, wenn die Entity zB. keinen PropertyChangeSupport bietet oder haben kann/darf.

Vielleciht habe ich mal wieder auch nur zu kompliziert gedacht :)
Es geht auch ohne Wrapper, wenn es denn wirklich nur der PropertyChangeSupport ist um den es geht.
Diesen würde ich nicht im DAO machen, das eigentliche Binding der Listeners an die Properties kann man ja auch schön auslagern (in einen Presenter, siehe MVP).

Denk dir nix, kann manchmal ganz schön vertrackt sein das ganze.

Bin heute Abend unterwegs und ab morgen nachmittag im Urlaub (davor auf Arbeit), denke nicht dass ich da telefonieren kann :(
 
G

Gast2

Gast
Hier hab ich mal einen möglichen einfachen Aufbau einer Anwendung dargestellt(siehe jar): Die View ist sehr einfach gehalten

Also Views:

Java:
package view;

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Main extends JFrame{
	
	public Main(){
		super("Beispiel MVC");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JPanel createView = new CreateView();
		JPanel listView = new ListView();
		JPanel lastView = new LastView();
		
		add(createView, BorderLayout.SOUTH);
		add(listView, BorderLayout.CENTER);
		add(lastView, BorderLayout.NORTH);
		
		pack();
	}
	
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {
				new Main().setVisible(true);	
			}
		});
	}

}
Java:
package view;

import java.awt.Dimension;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextField;

import controller.CreateKundeAction;
import db.Kunde;
import db.KundeHibernateImpl;

public class CreateView extends JPanel{

	private CreateKundeAction action;
	private JTextField  field;
	public CreateView(){
		super();
		setBorder(BorderFactory.createTitledBorder("Kunde anlegen"));
		action = new CreateKundeAction();

		field = new JTextField();
		field.setPreferredSize(new Dimension(100,25));
		add(field);
		add(new JButton(new AbstractAction("Anlegen") {
			
			@Override
			public void actionPerformed(ActionEvent arg0) {
				//Hier ne Factory oder Sosntiges benutzen
				Kunde k = new KundeHibernateImpl();
				k.setName(field.getText());
				action.setNewKunde(k);
				action.run();
				field.setText("");
			}
		}));
	}
}
Java:
package view;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import controller.CreateKundeAction;

public class ListView extends JPanel implements PropertyChangeListener{

	private CreateKundeAction action;
	private DefaultListModel listModel;
	private JList jList;
	
	public ListView(){
		super(new FlowLayout());
		setBorder(BorderFactory.createTitledBorder("Alle Kunden"));
		action = new CreateKundeAction();
		action.getKundenList().addPropertyChangeListener(this);
		listModel = new DefaultListModel();
		jList = new JList(listModel);
		jList.setPreferredSize(new Dimension(150,150));
		add(new JScrollPane(jList));	
	}

	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		if(evt.getPropertyName().equals("KUNDE_ADD")){
			listModel.addElement(evt.getNewValue());
		}
		
	}
}
Java:
package view;

import java.awt.BorderLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;

import controller.CreateKundeAction;

public class LastView extends JPanel implements PropertyChangeListener{

	private CreateKundeAction action;
	private JLabel jLabel;
	
	public LastView(){
		super();
		setBorder(BorderFactory.createTitledBorder("Letzter Kunde"));
		action = new CreateKundeAction();
		action.getKundenList().addPropertyChangeListener(this);
		jLabel = new JLabel();
		add(jLabel, BorderLayout.CENTER);	
	}

	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		if(evt.getPropertyName().equals("KUNDE_ADD")){
			jLabel.setText(evt.getNewValue().toString());
		}
		
	}
}

Controller Klassen
Java:
package controller;

public abstract class Action {
	
	public abstract void run();

}
Java:
package controller;

import service.KundenService;
import service.KundenServiceImpl;
import model.KundenModel;
import db.Kunde;

public class CreateKundeAction extends Action{

	//hab ich alles  mit Spring injected
	private static KundenModel kundenList = new KundenModel();
	private KundenService kundenService = new KundenServiceImpl();
	private Kunde newKunde;


	@Override
	public void run() {
		kundenService.createKunde(newKunde);
		kundenList.addKunde(newKunde);
	}

	public KundenModel getKundenList() {
		return kundenList;
	}


	public void setNewKunde(Kunde newKunde) {
		this.newKunde = newKunde;
	}



	public Kunde getNewKunde() {
		return newKunde;
	}

}

ModelKlasse
Java:
package model;


import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.List;

import db.Kunde;


public class KundenModel  {
    
    private List<Kunde> kundeList = new ArrayList<Kunde>();
	protected transient PropertyChangeSupport listeners = new PropertyChangeSupport(this);
    
    
    
    /**
     * Adds a property-change listener.
     * @param l the listener
     */
    public void addPropertyChangeListener(PropertyChangeListener l){
        if (l == null) {
            throw new IllegalArgumentException();
        }
        this.listeners.addPropertyChangeListener(l);
    }
    
    
    public void removePropertyChangeListener(PropertyChangeListener l){
        this.listeners.removePropertyChangeListener(l);
    }
    
    /**
     * Notificates all listeners to a model-change
     * @param prop the property-id
     * @param old the old-value
     * @param newValue the new value
     */
    protected void firePropertyChange(String prop, Object old, Object newValue){
        if (this.listeners.hasListeners(prop)) {
            this.listeners.firePropertyChange(prop, old, newValue);
        }
    }

    public void addKunde(Kunde o) {
        this.kundeList.add(o);
        // model has changed --> fire
        firePropertyChange("KUNDE_ADD", null, o); //$NON-NLS-1$
    }
    
    public void remove(Kunde o) {
        this.kundeList.remove(o);
//      model has changed --> fire
        firePropertyChange("KUNDE_REMOVE", o, null); //$NON-NLS-1$
    }
    
    public List<Kunde> getKundeList() {
		return new ArrayList<Kunde>(kundeList);
	}


}

So das wäre dein MVC:

Jetzt kommen deine Hibernate(fehlen die Annotations) Pojos:
Java:
package db;

public interface Kunde {

	Long getID();
	
    void setName(String name);

	String getName();

}
Java:
package db;

public class KundeHibernateImpl implements Kunde {

	private String name;

	@Override
	public Long getID() {
		// TODO Auto-generated method stub
		return null;
	}
	
	/* (non-Javadoc)
	 * @see dao.Kunde#setName(java.lang.String)
	 */
	@Override
	public void setName(String name) {
		this.name = name;
	}

	/* (non-Javadoc)
	 * @see dao.Kunde#getName()
	 */
	@Override
	public String getName() {
		return name;
	}
	
	@Override
	public String toString() {
		return name;
	}


}

Der Service, dort kommt u.a. deine BuLogik und Transaktionshandlling rein, welcher oben im Controller ausgeführt wird:
Java:
package service;

import java.util.List;

import db.Kunde;

public interface KundenService {

	List<Kunde> getKunden();

	void createKunde(Kunde kunde);

}

Java:
package service;

import java.util.List;

import dao.HibernateKundenDAOImpl;
import dao.KundenDAO;
import db.Kunde;

public class KundenServiceImpl implements KundenService{
        
		//Hab ich immer mit Spring injected
//		private KundenDAO kundenDAO;
	
	private KundenDAO kundenDAO = new HibernateKundenDAOImpl();
	
        /* (non-Javadoc)
		 * @see service.KundenService#getKunden()
		 */
        @Override
		public List<Kunde> getKunden(){
            return kundenDAO.getAllKunde();
        }
        
        /* (non-Javadoc)
		 * @see service.KundenService#createKunde(dao.Kunde)
		 */
        @Override
		public void createKunde(Kunde kunde){
        	kundenDAO.createKunde(kunde);
        }
        
}

DAO Klassen für den DB Zugriff:

Java:
package dao;

import java.util.List;

import db.Kunde;

public interface KundenDAO {

	Kunde createKunde(Kunde kunde);

	List<Kunde> getAllKunde();

}

Java:
package dao;

import java.util.ArrayList;
import java.util.List;

import db.Kunde;

public class HibernateKundenDAOImpl implements KundenDAO{
 
//    private SessionFactory sessionFactory;
    
    /* (non-Javadoc)
	 * @see dao.KundenDAO#createKunde(db.Kunde)
	 */
    @Override
	public Kunde createKunde(Kunde kunde) {
    	System.out.println("Speicher Kunde "+ kunde+ "in der DB ab");
//        return (Kunde) sessionFactory.getCurrentSession().save(KundeHibernateImpl.class, kunde);
       return null; 
    }
    /* (non-Javadoc)
	 * @see dao.KundenDAO#getAllKunde()
	 */
    @Override
	public List<Kunde> getAllKunde() {
//        Criteria crit = sessionFactory.getCurrentSession().createCriteria(KundeHibernateImpl.class);
//        return crit.list();
    	return new ArrayList<Kunde>();
    }
}


So mal für den Anfang ^^... Vielleicht kann maki nach seinem Urlaub noch bessere Vorschlähe bringen ;)
 

Anhänge

  • mvc.jar
    15,8 KB · Aufrufe: 5

Eldorado

Bekanntes Mitglied
Vielen Dank Sir Wayne dass du dir so Arbeit gemacht hast! Ich bin grade dabei auf Linux umzusteigen und werde mir dein Beispiel heute Abend mal zu Gemüte führen.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
thor_norsk Java - Allgemeine - Frage AWT, Swing, JavaFX & SWT 14
thor_norsk Allgemeine Frage AWT, Swing, JavaFX & SWT 10
M Frage zu Java Bundesligaverwaltung AWT, Swing, JavaFX & SWT 7
thor_norsk Allgemeine Frage AWT, Swing, JavaFX & SWT 9
E Frage zum Textfeld AWT, Swing, JavaFX & SWT 8
H Swing JMenu aufgeklappt oder nicht - Wie frage ich das ab? AWT, Swing, JavaFX & SWT 5
pkm Frage wegen java.lang.IllegalStateException bei DocumentListener AWT, Swing, JavaFX & SWT 4
D Frage zu ActionListenern und AvtionEvents AWT, Swing, JavaFX & SWT 2
ralfb1105 JavaFX Daten zwischen Controllern austauschen- neue Frage AWT, Swing, JavaFX & SWT 7
F JavaFX Frage zum Logging AWT, Swing, JavaFX & SWT 6
E Prinzip: wie man Ereignisse in einer GUI verarbeit. Frage zum Design? AWT, Swing, JavaFX & SWT 10
ralfb1105 Swing Frage zu SwingWorker Verhalten bei cancel() AWT, Swing, JavaFX & SWT 2
J Frage zu setuserdata AWT, Swing, JavaFX & SWT 1
N Frage zu ListView AWT, Swing, JavaFX & SWT 11
L 2D-Grafik Frage zu Ellipse2D.Double, Abfrage, ob Punkt enthalten ist funktioniert nicht AWT, Swing, JavaFX & SWT 3
T Frage zu GUI - Button soll Objekt erfassen AWT, Swing, JavaFX & SWT 2
J Event Handling Frage zu der Funktion addActionListener AWT, Swing, JavaFX & SWT 2
J Frage zur objektorentierten Swing Programmierung AWT, Swing, JavaFX & SWT 10
T JavaFX Frage zum FX-Loader AWT, Swing, JavaFX & SWT 3
B drawRect Frage und Aufgabenstellung AWT, Swing, JavaFX & SWT 10
fLooojava GridLayout - Frage bezüglich Kachelgröße AWT, Swing, JavaFX & SWT 5
S Frage zu java.awt.EventQueue AWT, Swing, JavaFX & SWT 1
J Frage zu Java Projekt [2D Game] AWT, Swing, JavaFX & SWT 3
M Swing Grundlegende Frage zu SWING mit WindowBuilder AWT, Swing, JavaFX & SWT 11
M Frage zum Loggen von Fehlern AWT, Swing, JavaFX & SWT 3
T Swing API Frage zu Verzeichnisbäumen und JTree AWT, Swing, JavaFX & SWT 1
M Thread-Frage in SWT AWT, Swing, JavaFX & SWT 1
Q Cursor Frage AWT, Swing, JavaFX & SWT 8
W JavaFX TableView frage AWT, Swing, JavaFX & SWT 5
H Taschenrechnerprojekt in Javafx - Frage zu den Buttons in FXML AWT, Swing, JavaFX & SWT 1
I Grundsätzliche Frage zu ItemListener AWT, Swing, JavaFX & SWT 11
X Kurze Frage zu JPopup AWT, Swing, JavaFX & SWT 3
D Swing [Frage] ComboBox + Label AWT, Swing, JavaFX & SWT 3
D Frage zu JFrame und Graphics AWT, Swing, JavaFX & SWT 4
J Swing Frage zur Vorgehensweise (JTable?, JLabels?) AWT, Swing, JavaFX & SWT 8
S Frage zu Jtable / CellEditor AWT, Swing, JavaFX & SWT 1
kaoZ Frage zum einfügen von Componenten AWT, Swing, JavaFX & SWT 14
N Swing JTable anfänger frage AWT, Swing, JavaFX & SWT 2
S GridBagLayout-Frage AWT, Swing, JavaFX & SWT 1
V 2D-Grafik Frage zum Graphics Objekt AWT, Swing, JavaFX & SWT 2
F Swing JComboBox - Frage zur Größe AWT, Swing, JavaFX & SWT 11
G noch eine Frage zum EventDispachThread AWT, Swing, JavaFX & SWT 4
D MVC Frage AWT, Swing, JavaFX & SWT 6
Z Flackern trotz Offscreen Image / Doublebuffer, (+ Frage zu Pixelvergleich) AWT, Swing, JavaFX & SWT 25
GianaSisters 2D-Grafik BufferedImage.getSubimage - Frage AWT, Swing, JavaFX & SWT 7
M Frage zu KeyListener bzgl. JApplet AWT, Swing, JavaFX & SWT 3
M Frage zu Threads AWT, Swing, JavaFX & SWT 3
N Swing JComboBox Frage AWT, Swing, JavaFX & SWT 5
Luk10 g.drawString funktioniert nicht + Frage zur Text-Rendering Qualität AWT, Swing, JavaFX & SWT 7
Luk10 Frage zu Farb-Komposition AWT, Swing, JavaFX & SWT 9
K Gui Layout Frage AWT, Swing, JavaFX & SWT 5
V SWT Import Wizard - frage zur WizardPage AWT, Swing, JavaFX & SWT 5
N Swing Frage JXMapviewer AWT, Swing, JavaFX & SWT 4
GUI-Programmer Wieder ne Layout Frage AWT, Swing, JavaFX & SWT 11
GUI-Programmer LayoutManager Kurze Layout Frage - eine komponente mittig? AWT, Swing, JavaFX & SWT 5
lumo SWT Zeichnen bescheunigen bzw eine allg. Frage AWT, Swing, JavaFX & SWT 8
H Frage zu übergebenem Vector bzw. Boolean AWT, Swing, JavaFX & SWT 3
C 2D-Grafik BufferedImage laden, Frage zum Code AWT, Swing, JavaFX & SWT 2
VfL_Freak Swing Frage zu "new JPasswordField( 10 )" AWT, Swing, JavaFX & SWT 6
H Frage zu WindowBuilder Pro AWT, Swing, JavaFX & SWT 3
C Frage/Problem mit Jpanel AWT, Swing, JavaFX & SWT 4
S Frage zu TextArea AWT, Swing, JavaFX & SWT 2
GUI-Programmer Zeichnen in Swing - Frage AWT, Swing, JavaFX & SWT 6
Luk10 Frage zu Mouseevents AWT, Swing, JavaFX & SWT 7
J Refreshing Swing Frage AWT, Swing, JavaFX & SWT 10
F Frage zu Event KeyTyped bei jPanel AWT, Swing, JavaFX & SWT 4
A Frage zu StringBuilder AWT, Swing, JavaFX & SWT 2
S allg. Frage zur GUI-Architektur AWT, Swing, JavaFX & SWT 5
A Frage zu JDialog AWT, Swing, JavaFX & SWT 3
A Frage zur Methode matches() AWT, Swing, JavaFX & SWT 2
P LayoutManager Verständnis-Frage GridBagLayout AWT, Swing, JavaFX & SWT 7
H Allgemeine Frage zu Grafikfähigkeiten von Java AWT, Swing, JavaFX & SWT 24
D Repaint Frage, Design Frage AWT, Swing, JavaFX & SWT 2
Jats Frage zu JLabel & JTextField AWT, Swing, JavaFX & SWT 4
Y frage zu BufferedImage AWT, Swing, JavaFX & SWT 7
hdi Swing Frage zu invokeAndWait() Exceptions AWT, Swing, JavaFX & SWT 8
P Swing Frage zu paintComponent/getGraphics AWT, Swing, JavaFX & SWT 4
M Frage nach Swing Element AWT, Swing, JavaFX & SWT 3
S Frage zu Graphics2D AWT, Swing, JavaFX & SWT 3
T AWT Frage zu AWT AWT, Swing, JavaFX & SWT 5
B Frage zu Swing,Threads, SwingWorker und Socket Communikation AWT, Swing, JavaFX & SWT 4
F unspezifizierte Frage zu JTable/ Model AWT, Swing, JavaFX & SWT 6
B SWT Frage zu MVC und Data-Binding AWT, Swing, JavaFX & SWT 8
T LookAndFeel Look and Feel Frage AWT, Swing, JavaFX & SWT 2
J Java2D Kreis/Kurven Frage AWT, Swing, JavaFX & SWT 2
P Kurze Frage zur Gestaltung eines vertikalen Menüs AWT, Swing, JavaFX & SWT 2
Dit_ Frage zum Thema SwingUtilities.invokeLater AWT, Swing, JavaFX & SWT 5
G Frage zu processMouseEvent AWT, Swing, JavaFX & SWT 6
M Zoomen in ein JPanel... und eine andere kleine Frage AWT, Swing, JavaFX & SWT 3
D Swing implementierungs-technische Frage zu JList/AbstractListModel AWT, Swing, JavaFX & SWT 7
C Event Frage AWT, Swing, JavaFX & SWT 7
A Frage zu GridLayout AWT, Swing, JavaFX & SWT 4
F Frage zu WindowListeners AWT, Swing, JavaFX & SWT 2
E einfache Frage:warum ist Hintergrund grau ? AWT, Swing, JavaFX & SWT 24
E einfache Frage zu paintComponent und Graphics AWT, Swing, JavaFX & SWT 7
C Frage zu ActionListenern AWT, Swing, JavaFX & SWT 7
D Frage @ someActionEvent.getActionCommand() AWT, Swing, JavaFX & SWT 2
Kr0e Allgemeine Frage zu Java2D (Eigene Impl.) AWT, Swing, JavaFX & SWT 18
L Einfache Layout Frage für Applet -> Was mache ich bloss falsch? AWT, Swing, JavaFX & SWT 2
N Swing Frage zu modalem JDialog. AWT, Swing, JavaFX & SWT 16

Ähnliche Java Themen

Neue Themen


Oben