Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Ich plane eine Java Desktop Anwendung basierend auf Swing zu erstellen. Dort will ich dann auch das MVC Model richtig anwenden. Ich hab dazu einiges schon gelesen und werde das MVC nach dem Beispiel von Java SE Application Design With MVC erstellen.
Die Informationen die im View angezeigt werden befinden sich dort stehts im Model. Das Model symbolisiert also ein Objekt, das die Daten "temporär" zwischenspeichert. Ein Model kann danach so aussehen (Darstellung stark verkürzt):
Java:
/** code drüber */
class XYZModel extends AbstractModel implements ABC
{
private String DEF;
private int GHI;
//...
public void getDEF();
}
Dadurch ergibt sich dann mir folgendes Problem: Wie lassen sich diese Model-Objekte sinnvoll abspeichern (die Daten in den Objekten)?
Muss für sowas JPA oder sowas wie Hibernate verwendet werden, um die Daten sinnvoll zu speichern und selbstverständlich auch zu laden und verändern?
Die Model kannst du natürlich mit JPA abspeichern über Annotationen oder über ein orm.xml.
Musst halt die entsprechenden Regeln und Conventions einhalten.
Die Model kannst du natürlich mit JPA abspeichern über Annotationen oder über ein orm.xml.
Musst halt die entsprechenden Regeln und Conventions einhalten.
Ja, den Link hatte ich bereits bei der Forensuche gefunden .
Für Models heißt das dann:
Einfügen von Annotations oder über orm.xml. Das speichern eines Models (also der Daten) erfolgt dann z.B. durch Aufruf eines EntityManagers, der dieses Model "verwaltet".
Ja, den Link hatte ich bereits bei der Forensuche gefunden .
Für Models heißt das dann:
Einfügen von Annotations oder über orm.xml. Das speichern eines Models (also der Daten) erfolgt dann z.B. durch Aufruf eines EntityManagers, der dieses Model "verwaltet".
Danke werde ich mir dann anschauen.
Bin erst beim Designen des Views.
Eine Frage zu den Models:
Entities stelle Models dar. In der View müssen, z.B. in einer JTable mehrere Zeilen dargestellt werden. Jede Zeile = ein Datensatz. Daraus ergibt sich das jeder Datensatz ein Objekt der Klasse "DatensatzModell" (ein Entity) ist.
Wie macht man das jetzt richtig?
Erstellt man eine HauptKlasse die alle Entities-Objekte enthält und die Entities werden in einer List (oder ähnlichem) "gespeichert". Die HauptKlasse verwaltet dann quasi die Objekte in Form eines Zwischenspeichers. Objekte können über getter/setter-Methoden geladen werden z.B. mit lazy-loading.
Beispiel (gekürzt):
Entity-Kunde.
Java:
@Entity
class Kunde {
private int id;
//Setter/Getter Methoden
public getId();
punlic setId();
"HauptModel"
Java:
class ModelVerwalter{
private Set kunden;
public Set getKunden()
{
//Lade Kunden nach API des jeweiligen ORMs
}
Wenn ich das so mache, dann komm ich in das Problem das das View nicht weiß welches Objekt es jetzt ansprechen muss (bzw. vom Controller angesprochen werden muss) um Daten zu ändern.
Gibt es 3 Kunden-Objekte, jeder füllt z.B. eine Zeile in einer JTable.
Es erfolgt ein Aufruf eines Listeners, der auf den Controller (den Mediator) mappt. Der Controller kann herausfinden welche Zeile selected ist.
Wie erkennt er nun welches Objekt selected ist, er kennt ja nur die Zeile!?
Ich denke wahrscheinlich nur zu kompliziert, aber es stellt für mich ein richtiges Problem dar, Model-Objekte richtig zu verwalten.
ich muss wahrscheinlich eigene TableModels, Lists etc. für diese Komponenten erzeugen, richtig?
Dort kann ich die einmal geladenen Objekte "speichern".
Ja ganz normaler Aufbau, einem MVC entsprechend.
Über den EntityManager können Entities-Objekte aus der Datenbank erstellt werden.
Die füge ich z.B. in eine JTable ein => das ist nur möglich mit einer Klasse die AbstractTableModel erweitert (oder mit Beans Binding). Ich hatte da lediglich einige Denkfehler.
Nur durch ein eigenes TableModel kann ein Objekt richtig in der Tabelle angezeigt werden (zuordnung der Objekt-Felder zu den Rows / Cols der Tabelle). Nur durch ein TableModel kann ich, bei Aufruf der Methode getSelectedRow() genau das ausgewählte Objekt wieder bekommen.
Ich hatte davor einen Aufbau das die Objekte außerhalb (ohne eignes TableModel) mit setValueAt() in der Tabelle dargestellt wurden. Das führt dann später zu Problemen, dass ich nicht wissen kann, welches Objekt genau ausgewählt ist in der Tabelle.
Ja ganz normaler Aufbau, einem MVC entsprechend.
Über den EntityManager können Entities-Objekte aus der Datenbank erstellt werden.
Die füge ich z.B. in eine JTable ein => das ist nur möglich mit einer Klasse die AbstractTableModel erweitert (oder mit Beans Binding). Ich hatte da lediglich einige Denkfehler.
AbstractTableModel erweitert (oder mit Beans Binding). Ich hatte da lediglich einige Denkfehler.
Nur durch ein eigenes TableModel kann ein Objekt richtig in der Tabelle angezeigt werden (zuordnung der Objekt-Felder zu den Rows / Cols der Tabelle). Nur durch ein TableModel kann ich, bei Aufruf der Methode getSelectedRow() genau das ausgewählte Objekt wieder bekommen.
Ich hatte davor einen Aufbau das die Objekte außerhalb (ohne eignes TableModel) mit setValueAt() in der Tabelle dargestellt wurden. Das führt dann später zu Problemen, dass ich nicht wissen kann, welches Objekt genau ausgewählt ist in der Tabelle.
Ja kommt drauf wenn du Swing verwendest kann das schon passen.
Deine Probleme sind einfach dass du kein Plan von einer JTable hast oder? Solltest erst mal das Tutorial zur JTable durchmachen
Die Notifications und die Struktur sind vorhanden.
Wo ich die Entites lade: Bisher noch garnicht - an dem Punkt der Anwendung bin ich noch nicht angelangt. Ich habe zuerst sämtliche Views gerade erstellt.
Wo habe ich sie vor zu laden: Es gibt viele Unterschiedliche Varianten des MVC Patterns. Wenn bei mir ein Modell ein Entity darstellt, so kann dieses entweder nur von einem Modell geladen werden, dass kein Entity ist - also die Logik zum laden der Entites ist in einem weiteren Modell, oder sie werden im Controller geladen.
Ja kommt drauf wenn du Swing verwendest kann das schon passen.
Deine Probleme sind einfach dass du kein Plan von einer JTable hast oder? Solltest erst mal das Tutorial zur JTable durchmachen
Das Problem ist nicht die JTable an sich, sondern dass ich das erste mal mit Entities arbeite und diese auch irgendwie sinnvoll benutzen möchte.
In einer vorherigen Anwendung hatte ich alles durch direkte SQL Queries gelöst. Das bringt je komplexer die Datenstruktur wird jedoch viele Probleme, deswegen JPA.
Die Notifications und die Struktur sind vorhanden.
Wo ich die Entites lade: Bisher noch garnicht - an dem Punkt der Anwendung bin ich noch nicht angelangt. Ich habe zuerst sämtliche Views gerade erstellt.
Wo habe ich sie vor zu laden: Es gibt viele Unterschiedliche Varianten des MVC Patterns. Wenn bei mir ein Modell ein Entity darstellt, so kann dieses entweder nur von einem Modell geladen werden, dass kein Entity ist - also die Logik zum laden der Entites ist in einem weiteren Modell, oder sie werden im Controller geladen.
Wie gesagt dass hat NICHTS mehr mit MVC zu tun!!!!
Deine Model sollten wiederverwendbar sein, denkst du da ist es schlaub JPA einzupflanzen?
Normalerweise solltes du einen Service machen der auf den EM zugreift.
Das Problem ist nicht die JTable an sich, sondern dass ich das erste mal mit Entities arbeite und diese auch irgendwie sinnvoll benutzen möchte.
In einer vorherigen Anwendung hatte ich alles durch direkte SQL Queries gelöst. Das bringt je komplexer die Datenstruktur wird jedoch viele Probleme, deswegen JPA.
Du programmierst genau gleich es gibt keinen Unterschied. Ich versteh es nicht sorry mach mal ein KSKB was genau dein Problem ist.
Du musst auch aufpassen wenn du JPA verwendest, wenn du attach Objekte in der GUI veränderst, beim nächsten commit kommt alles in die DB. Also solltest du dich mit JPA beschäftigen und deine Architektur fertig ausdenken.
Wie gesagt dass hat NICHTS mehr mit MVC zu tun!!!!
Deine Model sollten wiederverwendbar sein, denkst du da ist es schlaub JPA einzupflanzen?
Normalerweise solltes du einen Service machen der auf den EM zugreift.
Du programmierst genau gleich es gibt keinen Unterschied. Ich versteh es nicht sorry mach mal ein KSKB was genau dein Problem ist.
Du musst auch aufpassen wenn du JPA verwendest, wenn du attach Objekte in der GUI veränderst, beim nächsten commit kommt alles in die DB. Also solltest du dich mit JPA beschäftigen und deine Architektur fertig ausdenken.
So, ich brauchte jetzt ein wenig Zeit zum überdenken des Ganzen.
Im Grunde stimmt doch dann folgender Aufbau:
View-Controller->Services->DAO->DAO-Model
Der Service ist zuständig für die Verwaltung des EM und führt gewisse Sachen damit aus. Über ein DAO wird Unabhängigkeit und Wiederverwendbarkeit geschaffen. Das View muss nicht direkt über das Model bescheidwissen, dass muss nur der Controller. Dabei wird ein Interface implementiert, dass Properties und Methoden für ein Model definiert. Somit ist es dem Controller/View egal ob es ein HibernateKundenModel oder ein EclipselinkKundenModel bekommt, solange beide das Interface KundenModel implementieren.
Stimmt das jetzt so?
Wenn ja dann geb ich die auch noch nen KSKB nachher.
So, ich brauchte jetzt ein wenig Zeit zum überdenken des Ganzen.
Im Grunde stimmt doch dann folgender Aufbau:
View-Controller->Services->DAO->DAO-Model
Der Service ist zuständig für die Verwaltung des EM und führt gewisse Sachen damit aus. Über ein DAO wird Unabhängigkeit und Wiederverwendbarkeit geschaffen. Das View muss nicht direkt über das Model bescheidwissen, dass muss nur der Controller. Dabei wird ein Interface implementiert, dass Properties und Methoden für ein Model definiert. Somit ist es dem Controller/View egal ob es ein HibernateKundenModel oder ein EclipselinkKundenModel bekommt, solange beide das Interface KundenModel implementieren.
Stimmt das jetzt so?
Wenn ja dann geb ich die auch noch nen KSKB nachher.
Jop passt , ich hab hier sogar ein KSKB hier im Forum welches genau diesen Aufbau darstellt.
Wie gesagt bei Controller musst du aufpassen, es gibt imho GUI-Controller (UI abhängig z.B. in Swing die Listener) und Controller welche UI unabhängig sind und deine Services aufruft.
Im eigentlichen MVC sind die Controller eigentlich die UI abhängigen also in Swing jeder Listener ist ein Controller...
Jop passt , ich hab hier sogar ein KSKB hier im Forum welches genau diesen Aufbau darstellt.
Wie gesagt bei Controller musst du aufpassen, es gibt imho GUI-Controller (UI abhängig z.B. in Swing die Listener) und Controller welche UI unabhängig sind und deine Services aufruft.
Im eigentlichen MVC sind die Controller eigentlich die UI abhängigen also in Swing jeder Listener ist ein Controller...
package coreplugin.dao;
import coreplugin.db.QueueEntry;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: Dennis
* Date: 03.01.12
* Time: 18:50
* To change this template use File | Settings | File Templates.
*/
interface QueueDao {
Object createQueueEntry(QueueEntry queueEntry);
Object deleteQueueEntry(QueueEntry queueEntry);
Object updateQueueEntry(QueueEntry queueEntry);
List getAllQueueEntry();
Object findQueueEntry(int identifier);
Object getFirstQueueEntry();
}
EclipselinkQueueDaoImpl
Java:
package coreplugin.dao;
import coreplugin.db.QueueEntity;
import coreplugin.db.QueueEntry;
import coreplugin.util.EclipseUtil;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: Dennis
* Date: 03.01.12
* Time: 18:53
* To change this template use File | Settings | File Templates.
*/
@SuppressWarnings("HardCodedStringLiteral")
public class EclipselinkQueueDaoImpl implements QueueDao {
private final EntityManager entityManager = EclipseUtil.getEntityManager();
@Override
public QueueEntry createQueueEntry(QueueEntry queueEntry) {
entityManager.persist(queueEntry);
return queueEntry;
}
@Override
public QueueEntry deleteQueueEntry(QueueEntry queueEntry) {
entityManager.remove(queueEntry);
return queueEntry;
}
@Override
public QueueEntry updateQueueEntry(QueueEntry queueEntry) {
entityManager.merge(queueEntry);
return queueEntry;
}
@Override
public List getAllQueueEntry() {
return entityManager.createQuery("Select q from QueueEntity q", QueueEntity.class).getResultList();
}
@Override
public QueueEntry findQueueEntry(int identifier) {
Query query = entityManager.createQuery("select q from QueueEntity q where q.identity in :identifier");
query.setParameter("identifier", identifier);
return (QueueEntry) query.getSingleResult();
}
@Override
public QueueEntry getFirstQueueEntry() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
}
QueueModel
Java:
package coreplugin.db;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: Dennis
* Date: 03.01.12
* Time: 18:08
* To change this template use File | Settings | File Templates.
*/
public class QueueModel {
private final List<QueueEntry> queueEntryList = new ArrayList<QueueEntry>();
protected final 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 addQueueEntry(QueueEntry queueEntry)
{
queueEntryList.add(queueEntry);
firePropertyChange("queueEntryAdded", null, queueEntry);
}
public List<QueueEntry> getQueueList() {
return new ArrayList<QueueEntry>(queueEntryList);
}
}
QueueViewPanel
Java:
package coreplugin.view;
import coreplugin.controller.QueueController;
import coreplugin.dao.EclipselinkQueueDaoImpl;
import coreplugin.db.QueueEntry;
import coreplugin.db.QueueTableModel;
import org.chaosfisch.mvc.view.AbstractViewPanel;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.util.List;
public final class QueueViewPanel extends AbstractViewPanel {
private final QueueController controller;
private JPanel queuePanel;
public JTable queueTable;
private JButton startenButton;
private JButton stoppenButton;
private JButton arrowTop;
private JButton arrowUp;
private JButton arrowDown;
private JButton arrowBottom;
private JComboBox queueFinishedList;
private JButton editButton;
private JButton deleteButton;
private JComboBox queueViewList;
private JTextField titleTextField;
private JTextField fileTextField;
private JTextField starttimeTextField;
private JTextField statusTextField;
private JButton abortButton;
private JTextField uploadedBytesTextField;
private JTextField etaTextField;
private JProgressBar progressbar;
private final QueueTableModel queueTableModel;
public QueueViewPanel(QueueController controller) {
this.controller = controller;
controller.getQueueList().addPropertyChangeListener(this);
List<QueueEntry> list = controller.getQueueList().getQueueList();
queueTableModel = new QueueTableModel(list);
queueTable.setModel(queueTableModel);
//Hier eine Factory noch einsetzen.
EclipselinkQueueDaoImpl elipselinkQueueDao = new EclipselinkQueueDaoImpl();
queueTableModel.addQueueEntryList(elipselinkQueueDao.getAllQueueEntry());
initComponents();
initListeners();
}
private void initComponents() {
queueTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
private void initListeners() {
//Start, Stop, End Listeners
startenButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
controller.startQueue();
}
});
stoppenButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
controller.stopQueue();
}
});
abortButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
controller.abortUpload();
}
});
queueFinishedList.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
controller.changeQueueFinished(e.getItem());
}
});
//ADD Arrow Listeners
arrowTop.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
controller.moveTop(queueTable.getSelectedRow());
}
});
arrowUp.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
controller.moveUp(queueTable.getSelectedRow());
}
});
arrowDown.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
controller.moveDown(queueTable.getSelectedRow());
}
});
arrowBottom.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
controller.moveBottom(queueTable.getSelectedRow());
}
});
//Edit, Delete, View Buttons
editButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow = queueTable.getSelectedRow();
if (queueTableModel.hasQueueEntryAt(selectedRow)) {
controller.editEntry(queueTableModel.getQueueEntryAt(selectedRow));
}
}
});
deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow = queueTable.getSelectedRow();
if (queueTableModel.hasQueueEntryAt(selectedRow)) {
controller.deleteEntry(queueTableModel.getQueueEntryAt(selectedRow));
queueTableModel.removeQueueEntryAt(selectedRow);
queueTable.changeSelection(selectedRow-1, 0, false, false);
}
}
});
queueViewList.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
controller.changeQueueView(e.getItem());
}
});
}
public JPanel getQueuePanel() {
return queuePanel;
}
@SuppressWarnings("CallToStringEquals")
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(QueueController.ETA_PROPERTY)) {
etaTextField.setText(evt.getNewValue().toString());
} else if (evt.getPropertyName().equals(QueueController.FILE_PROPERTY)) {
fileTextField.setText(evt.getNewValue().toString());
} else if (evt.getPropertyName().equals(QueueController.PROGRESS_PROPERTY)) {
progressbar.setValue(Integer.parseInt(evt.getNewValue().toString()));
} else if (evt.getPropertyName().equals(QueueController.STARTTIME_PROPERTY)) {
starttimeTextField.setText(evt.getNewValue().toString());
} else if (evt.getPropertyName().equals(QueueController.STATUS_PROPERTY)) {
statusTextField.setText(evt.getNewValue().toString());
} else if (evt.getPropertyName().equals(QueueController.TITLE_PROPERTY)) {
titleTextField.setText(evt.getNewValue().toString());
} else if (evt.getPropertyName().equals(QueueController.UPLOADED_BYTES_PROPERTY)) {
uploadedBytesTextField.setText(evt.getNewValue().toString());
}
}
}
QueueController
Java:
package coreplugin.controller;
import coreplugin.db.QueueEntry;
import coreplugin.db.QueueModel;
import org.chaosfisch.mvc.controller.AbstractController;
public class QueueController extends AbstractController {
public static final String STATUS_PROPERTY = "Status"; //NON-NLS
public static final String TITLE_PROPERTY = "Title"; //NON-NLS
public static final String FILE_PROPERTY = "File"; //NON-NLS
public static final String STARTTIME_PROPERTY = "Starttime"; //NON-NLS
public static final String UPLOADED_BYTES_PROPERTY = "Uploaded Bytes"; //NON-NLS
public static final String ETA_PROPERTY = "ETA"; //NON-NLS
public static final String PROGRESS_PROPERTY = "Progress"; //NON-NLS
private static final QueueModel queueList = new QueueModel();
public void startQueue() {
}
public void stopQueue() {
}
public void abortUpload() {
}
public void changeQueueFinished(Object item) {
}
public void moveTop(int selectedRow) {
}
public void moveUp(int selectedRow) {
}
public void moveDown(int selectedRow) {
}
public void moveBottom(int selectedRow) {
}
public void changeQueueView(Object item) {
}
public void deleteEntry(QueueEntry queueEntityAt) {
}
public void editEntry(QueueEntry queueEntityAt) {
}
public QueueModel getQueueList() {
return queueList;
}
}
So kurz zusammenfassend noch dazu:
Es muss noch die Service-Schicht ausgebaut werden. Es kommt eine Klasse QueueServiceImpl mit Interface QueueService hinzu. Dieser "Service" führt Operationen über das DAO aus, wodurch mit der Datenbank kommuniziert wird.
Einige PropertyChangeEvents wie queueEntryAdded müssen noch verarbeitet werden.
Nach diesem Aufbau passiert doch eigentlich folgendes:
User macht eine Eingabe über das View. Dieses mappt auf den Controller. Der Controller führt Aktionen aus und kann (muss aber nicht) einen Datenbankzugriff einfordern. Dies geschieht über 2 Sachen:
1. Dem Service-Layer: Hier findet der direkte Zugriff über ein DAO auf die Datenbank statt. Hier werden keine PropertyChangeEvents gefeuert
2. Einem Model: Ihm wird das selbe Objekt übergeben. Das Model feuert anschließend ein PropertyChangeEvent, sodass sich das View updaten kann.
Ich seh grad, ich hab da vermutlich noch ein Fehler in der Umsetzung. Wenn ich es richtig sehe, dann kann ich die Klasse QueueTableModel und QueueModel mergen. Der Fehler kam wohl durch die Übernahme "deiner" Struktur.
Jetzt halt nur nochmal die Frage, passt das so, oder sollte ich noch was ändern?
So, hab jetzt mein QueueTableModel und mein QueueModel gemerged. Sollte das selbe darstellen.
Jetzt noch eine Frage:
Der Aufbau ist ja: View, Controller -> Service -> DAO
Warum benutzt man einen Service-Layer, in deinem KSKB macht der Service das selbe wie das DAO. Es gibt somit viel Coderedundanz. Gibt es also Gründe einen Service-Layer noch dazwischen zu setzen?
Edit: Achso, das man evtl sagt: Das DAO beinhaltet nur einfache Vorgänge wie: updaten, hinzufügen, entfernen, finden und alle zurückgeben.
Der Service hingegen kann mehrere DAO Funktionalitäten bündeln und viele weitere Aktionen durchführen!?
Ich geb mal wieder mein Senf dazu
1. Dein Interface von oben ist total unschön ein Interface sollte keine Variablen beinhalten, sondern nur Methoden vorgegeben nehm die raus und schreib diese in deine xxxxImpl rein.
2. Ich würde dir raten die JPA Annotationen dann an die Member Variable zu machen, da dass übersichtlicher ist.
3. Für CRUD Funktonalitäten brauchst du nicht unbedingt ein DAO, da der EntityManager typsicher ist und quasi dein DAO darstellt.
4. Du brauchst eine Service Schicht für das Transaktionshandling. In deinem Service Layer liegt deine Business Logik mit Fehlerbehandlung usw. Da musst du dir Gedanken machen was passiert bei Fehler xyz. Wie geht es weiter mit der Transaktion und vor allem muss dur dir Gedanken über die JPA Sachen machen bezüglich attach und dettach Objekten!!!
5. Würde ich keinen PropertyChange Support mehr verwenden. Der hat ein paar unschöne Nebeneffekte. z.B. kannst du einen GLEICHEN(!!!) Listener mehrmals deinem Model adden, aber beim remove wird er nur 1 mal entfernt.
Schau dir mal den EventBus an, finde persönlich sehr gelungen und einfach zu verstehen.
Ich geb mal wieder mein Senf dazu
1. Dein Interface von oben ist total unschön ein Interface sollte keine Variablen beinhalten, sondern nur Methoden vorgegeben nehm die raus und schreib diese in deine xxxxImpl rein.
2. Ich würde dir raten die JPA Annotationen dann an die Member Variable zu machen, da dass übersichtlicher ist.
4. Du brauchst eine Service Schicht für das Transaktionshandling. In deinem Service Layer liegt deine Business Logik mit Fehlerbehandlung usw. Da musst du dir Gedanken machen was passiert bei Fehler xyz. Wie geht es weiter mit der Transaktion und vor allem muss dur dir Gedanken über die JPA Sachen machen bezüglich attach und dettach Objekten!!!
5. Würde ich keinen PropertyChange Support mehr verwenden. Der hat ein paar unschöne Nebeneffekte. z.B. kannst du einen GLEICHEN(!!!) Listener mehrmals deinem Model adden, aber beim remove wird er nur 1 mal entfernt.
Schau dir mal den EventBus an, finde persönlich sehr gelungen und einfach zu verstehen.
Auf EventBus bin ich bereits gestoßen als ich nach Best Practices gesucht hatte. PropertyC. oder Oberserver. "Den Eventbus" entnehm ich doch aus dem Repositorie von Eventbus: Subversion — Java.net. Da brauch ich die ganz normale Eventbus.jar R 60?
So ungefähr hab ich mir das Gedacht vorhin. War mir aber nicht sicher.
Auf EventBus bin ich bereits gestoßen als ich nach Best Practices gesucht hatte. PropertyC. oder Oberserver. "Den Eventbus" entnehm ich doch aus dem Repositorie von Eventbus: Subversion — Java.net. Da brauch ich die ganz normale Eventbus.jar R 60?
Standalone client Anwendung? Falls ja
Wie gesagt ich denke du brauchst dann nicht extra eine DAO-Schicht, diese stellt dein EntityManager dar.
Ich würde sogar sagen dass du deinen AbstractController genauso wenig brauchst, wenn du einen Service Layer einbaust. Der AbstractController manchmal auch ServiceLocator genannt war dafür gesagt remote Services aufzurfen, aber wenn du keine hast, könntest die auch rein theoretisch weglassen.
Ich hab den EventBus noch nie selber eingebaut, der war in meinem Projekten schon immer im repo vorhanden.
Aber sonst sieht dein Aufbau soweit okay aus.
Ich würde dir noch Google Guice als DI Framework ans Herz legen, da es für deinen Fall leicht gewichtiger als Spring ist. Ist eigentlich ziemlich einfach zu verstehen und dann ist deine Anwendung wirklich sauber aufgebaut.
Standalone client Anwendung? Falls ja
Wie gesagt ich denke du brauchst dann nicht extra eine DAO-Schicht, diese stellt dein EntityManager dar.
Ich würde sogar sagen dass du deinen AbstractController genauso wenig brauchst, wenn du einen Service Layer einbaust. Der AbstractController manchmal auch ServiceLocator genannt war dafür gesagt remote Services aufzurfen, aber wenn du keine hast, könntest die auch rein theoretisch weglassen.
Ich hab den EventBus noch nie selber eingebaut, der war in meinem Projekten schon immer im repo vorhanden.
Aber sonst sieht dein Aufbau soweit okay aus.
Ich würde dir noch Google Guice als DI Framework ans Herz legen, da es für deinen Fall leicht gewichtiger als Spring ist. Ist eigentlich ziemlich einfach zu verstehen und dann ist deine Anwendung wirklich sauber aufgebaut.
Jo standalone client Anwendung.
Der AbstractController war nur von vorher noch drinnen, aber komplett leer.
Ich werde mir das DI Framework dann noch anschauen. Sieht erstmal mächtig kompliziert aus.
Was ich soweit verstanden habe: DI macht die Anwendungsteile unabhängiger. Unit Tests werden dadurch einfacher.
Aus:
Java:
public class QueueServiceImpl implements QueueService {
private final EntityManager entityManager = EclipseUtil.getEntityManager();
}
Muss dann sowas werden:
Java:
public class QueueServiceImpl implements QueueService{
private final EntityManager entityManager;
public QueueServiceImpl(EntitityManager em)
{
entityManager = em;
}
Wie das dann alles mit den Annotations funktioniert etc. muss ich noch genau durchlesen.
Jo standalone client Anwendung.
Der AbstractController war nur von vorher noch drinnen, aber komplett leer.
Ich werde mir das DI Framework dann noch anschauen. Sieht erstmal mächtig kompliziert aus.
Was ich soweit verstanden habe: DI macht die Anwendungsteile unabhängiger. Unit Tests werden dadurch einfacher.
Aus:
Wie das dann alles mit den Annotations funktioniert etc. muss ich noch genau durchlesen.
Genau es wird alles loser gekoppelt und bei JUnit Test kannst du einfacher deine Sachen mocken. So kannst du MockService Schreiben die nicht auf die DB zugreifen usw.
Außerdem musst du dich nicht mehr um Singeltons kümmern, weil du keine mehr hast.
Danke, schau ich mir an sobald ich durch die Guice Wiki durch bin.
Ich hab nun auch EventBus statt PropertyChange drinnen.
Eine Frage hätte ich da aber noch:
Controller Methode, wird vom View aufgerufen:
Java:
public void startQueue() {
EventBus.publish(Constants.UPLOAD_JOB, Constants.START_QUEUE);
}
In irgendeiner anderen Klasse befindet sich dann der Subscriber. Im Subscriber würde dann z.B. ein SwingWorker aufgerufen. Darf man das so, oder sollte man den Service im Controller direkt aufrufen?
In irgendeiner anderen Klasse befindet sich dann der Subscriber. Im Subscriber würde dann z.B. ein SwingWorker aufgerufen. Darf man das so, oder sollte man den Service im Controller direkt aufrufen?
Vesteh ich nicht... Wenn du etwas direkt aufrufen kannst, warum solltest du es nicht direkt aufrufen?
Der EventBus oder ein Notification ist dafür da auf etwas zu reagieren, wenn sich etwas ändert oder ausgelöst wird.