Re: Java in umfangreicheren Projekten
- From: "Sebastian Scheid" <mynewsgroup@xxxxxx>
- Date: Thu, 21 Jul 2005 01:33:13 +0200
"Christoph Kühn" <usenet@xxxxxxx> schrieb im Newsbeitrag
news:dbmgjk$2ap$1@xxxxxxxxxxxxxxxxxxxxxxxxxxxx
> Guten Abend,
> erstmal möchte ich mich für die vielen Anregungen bedanken, auch wenn ich
> mit einer solchen Abfuhr nicht rechnen konnte ;) Die Inhalte habe ich
> weitestgehend verstanden und sehe auch ein, dass ich eben eine vollkommene
> Kopplung durch die bisherige Vorgehensweise verursache.
>
> Ich habe mir in der kurzen Zeit bis jetzt ein paar Gedanken rund um die
> Ideen und meine bisherigen Vorstellungen gemacht. Der wesentliche Punkt
> ist für mich aber nach wie vor unklar. Dieser wesentliche Punkt drückt
> sich mir in der "Vermittlerrolle" zwischen Anwendungslogik und der
> Darstellung aus.
Kennst Du Dich mit MVC aus? Die Vermittlerrolle hat da der Controller, wobei
es eine gerndiskutierte Frage ist, wer zuerst da ist, wer wen instanziiert
und wer wen kennt (Kopplung). Ich will diese Diskussion jetzt mal nicht
aufgreifen sondern erzählen wie ich es in Deinem Fall machen würde.
Obwohl eine lose Kopplung zwischen den Programmteilen wünschenswert ist,
bekommst Du es nicht hin, gar keine Kopplungs zu haben. Stell Dir vor, die
Programmteile bieten einen bestimmten Dienst an, ohne von anderen
Programmteilen zu wissen (sie sind gar nicht gekoppelt). Z.B. hast Du ein
Server-Interface und ein UI-Interface. Du kommst aber nicht umhin das jemand
die Vermittlerrolle übernimmt und die beiden Programmteile verbindet. Das
wird meist eine dritte Klasse sein (Main, Application, Controller, ...), die
die "richtige" Implementationen der Interfaces instanziiert und dann z.B.
den Server der GUI übergibt. Die GUI kennt den Server, aber nicht umgekehrt.
>
> Angenommen es läge eine Serveranwendung zu Grunde. In einem Menü wären nun
> zwei Menuelemente "Server starten" und "Server stoppen" vorhanden.
> Folgende Dinge sollten möglich sein:
>
> - Die Menüelemente entsprechen in der Ansicht der aktuellen Logik (Server
> stoppen deaktiviert, wenn Server nichts läuft...)
> - Eine Betätigung eines Menüelements würde eine entsprechende Aktion
> hervorrufen (Server starten oder eben Server stoppen)
>
> Meine Realisierung der Darstellungslogik würde sich - zunächst mal ein
> wenig abstrakt - wie folgt ergeben:
>
> - die Menüinstanz implementiert einen "ServerStatusListener" und aufgrund
> dessen eine "serverStatusChanged-Methode". Das Menü registriert sich also
> als ServerStatusListener am Server und wird entsprechend informiert,
> woraufhin die Darstellung entsprechend angepasst wird.
>
> Hier ergibt sich ein wesentliches Problem. Wie komme ich nun an die
> entsprechende Serverinstanz (angenommen die Instanz würde schon
> existieren) oder wie sorge ich dafür, dass die Serverinstanz "global"
> verfügbar wird und auch für andere Darstellungskomponenten erreichbar ist?
> Ich muss ja meinen Listener bei dieser Instanz registrieren.
Wie oben schon erwähnt: die GUI kennt das Server-Interface, bekommt aber die
konkrete Instanz von außen hereingereicht, z.B. im Konstruktor. Wichig: wenn
die GUI schon von etwas abhängig ist, dann bitte nur von einem Interface!
Damit kannst Du den Server austauschen (RMIServer, DummyServer, ...), ohne
die GUI ändern zu müssen.
Die Alternative ist, die GUI vom Server unabhängig zu belassen. Dann ist die
GUI eine sehr dumme Ansammlung von Widgets, denen von außen wiederrum Leben
eingehaucht werden muss. Das sieht dann so aus, dass Du das UI-Interface um
alle mögichen Widget-Zugriffsmethoden aufblähst, die der Controller dann
benutzt, um z.B. die Actions zu registrieren. Sowas macht man höchstens in
kleinen Teilen einer GUI. Z.B. ein Dialog, den man wiederverwenden will.
Aber eine komplette Haupt-GUI baut man so IMHO nicht auf. Dann wird man
nämlich schnell wahnsinnig. Bei wirklich großen Projekten wie Eclipse wird
das evtl. anders sein. Dort hast Du allerdings den speziellen Fall, dass der
Eclipse Kern auf nichts spezialisiert ist und damit auch von wenig abhängig
ist. Das geniale daran ist halt, dass man mit diesen wenigen Abhängigkeiten
(Extension Points usw.) trotzdem unglaublich viel machen kann. Der Aufwand
dafür wird allerdings beträchtlich sein und lohnt will bei "normalen"
Projekten gut überlegt sein.
>
> Wäre also das Vorgehen korrekt, meinem Menü zur Instanzierung zwingend
> eine "ServerOwner"-Schnittstelle erbende Instanz (als Vermittler)
> vorzuschreiben?:
Der ServerOwner ist hier ein Teil zuviel. Was übernimmt der denn für eine
Aufgabe? Wie gesagt: reiche den Server (nicht den Owner) einfach in die GUI
hinein.
>
> public class Menu implements ServerStatusListener {
> private ServerOwner serverOwner;
> private MenuItem startServerMI;
> [...]
>
> public Menu(ServerOwner serverOwner) {
> this.serverOwner = serverOwner;
> this.serverOwner.getServer().addServerStatusListener(this);
> }
>
> public void initialize() {
> [...]
> this.starServerMI.addActionListener(new ActionListenr() {
> public void actionPerformed(ActionEvent e) {
> this.serverOwner.getServer().startServer();
> }
> });
> [...]
> }
>
> public void serverStatusChanged(ServerStatusChangeEvent e) {
> if(((Server)e.getSource()).getStatus() == Server.RUNNING)
> this.startServerMI.setEnabled(false);
> [...]
> }
> }
>
> Und wäre dann ein solcher Aufruf wie im anonymen ActionListener in Ordnung
> (oder auch hier Ereignisse feuern? - aber wie registrieren?)?
Das ist schon ok so. Die o.g. Alternative: die GUI kennt den Server nicht,
aber der Controller kennt ihn. Der Controller registriert einen
ActionListener bei Menu.starServerMI und implementiert ServerStatusListener.
Menu muss Zugriff auf startServerMI bieten, damit der Controller es enablen
und Listener registrieren kann.
Beispiel 1:
- keine Kopplung des Servers an die GUI
- GUI kennt Server-INTERFACE
class Main
....
Server server = new RMIServer();
UI ui = new UI(server);
class UI
....
private JMenuItem miStartServer;
private ServerStatusListener serverListener = new ServerStatusListener() {
void notify(ServerEvent) {
miStartServer.setEnabled(...);
}
};
// Konstruktor
UI(Server server) {
createWidgets();
layoutWidgets();
setActions(server);
}
void setActions(Server server) {
server.addListener(serverListener);
startButton.addActionListener(
...
server.start();
);
...
}
Beispiel 2:
- keine Kopplung des Servers an die GUI
- keine Kopplung der GUI an den Server
- GUI muss Zugriff auf Widgets gewähren => Kapselung aufgebrochen
class Main
....
Server server = new RMIServer();
UI ui = new UI();
server.addListener(new ServerStatusListener() {
void notify(ServerEvent) {
ui.getMiStartServer().setEnabled(...);
}
};
class UI
....
private JMenuItem miStartServer;
// Konstruktor
UI() {
createWidgets();
layoutWidgets();
// keine Actions
}
JMenuItem getMiStartServer() {
return ...
}
>
> Wäre dem so, dann wäre das alles wieder nicht entkoppelt. Eine Ebene höher
> würde ich mich beim Instanzieren der obigen Menü-Instanz fragen, woher ich
> denn nun die dazu nötige ServerOwner-Instanz bekomme. Versteht ihr mein
> Problem? ;)
> Wie schaffe ich eine entkoppelte Verbindung zwischen einem beliebigen
> Darstellungselement und Inhalten der Anwnedungslogik?! Ich komme schlicht
> und ergreifend nicht dran, ohne die Inhalte in Form von Verweisen von oben
> an nach unten durchzureichen.
>
> Vermutlich sehe ich aber nur den Wald vor lauter Bäumen nicht. HILFE ;)
Zusammengefasst: komplette Entkopplung geht nicht. Überlege wer von wem
abhängig sein darf und soll. Meist wird die UI von der Anwendungslogik
abhängig sein, denn die Logik willst Du ja in der SwingApp, in der WebApp
und in der Handy-Version benutzen, nicht wahr?
Soll die GUI auch entkoppelt sein (z.B. wenn sie generisch aufgebaut wird),
muss der Controller/Vermittler mehr Arbeit übernehmen. Das macht IMHO nur in
Spezialfällen Sinn.
Schöne Grüße
Sebastian
.
- References:
- Java in umfangreicheren Projekten
- From: Christoph Kühn
- Re: Java in umfangreicheren Projekten
- From: Sebastian Baechle
- Re: Java in umfangreicheren Projekten
- From: Christoph Kühn
- Java in umfangreicheren Projekten
- Prev by Date: [OT] news-server?
- Next by Date: Re: [Hibernate] Aus Mappingfile DB-Schema erzeugen
- Previous by thread: Re: Java in umfangreicheren Projekten
- Next by thread: Re: Java in umfangreicheren Projekten
- Index(es):