Trennung von GUI und Logik

Status
Nicht offen für weitere Antworten.
Hallo,
ich habe ein recht einfaches Problem, aber ich bekomme es einfach nicht hin.
Wie kann ich GUI und Logik sauber trennen?
Als Beispiel habe ich folgendes einfaches Beispiel geschrieben:


Hauptklasse:

Code:
public class mainclass {
    public static void main(String[] args) {
        meinfenster fenster = new meinfenster();
    }
   
    public static void test(){
        System.out.println("test");
    }
}

GUI-Klasse:
Code:
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class meinfenster extends JFrame implements ActionListener{
    public meinfenster() {
        this.setSize(300,100);
        this.setLocation(200,200);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        try {
            jbInit();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void jbInit() throws Exception {
        ibutton1.setText("TestButton");
        ibutton1.addActionListener(this);
        jLabel1.setHorizontalAlignment(SwingConstants.CENTER);
        jLabel1.setHorizontalTextPosition(SwingConstants.CENTER);
        jLabel1.setText("Test");
        this.getContentPane().add(ibutton1, java.awt.BorderLayout.SOUTH);
        this.getContentPane().add(jLabel1, java.awt.BorderLayout.CENTER);
        this.show();


    }

    JButton ibutton1 = new JButton();
    JLabel jLabel1 = new JLabel();
    public void actionPerformed(ActionEvent e) {

}

}
Nun meine Frage: Wie kann ich aus der GUI Klasse heraus die Methode test() aufrufen ohne das dabei die Mainclasse wieder den Actionlistener implementieren muss? Dazu muss das Event aus der GUI-Klasse ja an die mainclasse zurückgeliefert werden. Wie geht das?
 

hupfdule

Top Contributor
Indem du deiner GUI-Klasse eine Referenz auf die Logikklasse mitgibst. Am besten gleich im Konstruktor. Diese kann dann aus dem ActionListener heraus deren test() aufrufen.

Um das noch etwas sauberer zu handhaben (was allerdings nur in größeren Projekten lohnt), könnte die Logikklasse noch ein Interface implementieren und die GUI-Klasse erwartet dann nur eine Implementierung dieses Interfaces. Damit hättest du noch einmal die Abstraktion erhöht.

BTW: Laut Konventino werden Klassen in Java in PascalCase geschrieben. (MeinFenster statt meinfenster)
 

KSG9|sebastian

Top Contributor
deine Logik sieht z.B. so aus

Code:
interface Logik{
  public void test();
  public void ende();
  public void action();
  // noch mehr methodenkörper
}

class LogikImpl implements Logik{
   public LogikImpl(){
      MeinFenster mf = new MeinFenster(this);
   }
   public void action(){
      System.out.println("action performed");
   }
   public void test(){
      // do something
   }
   public void ende(){
      System.exit(1);
   }
}

Und deine Klasse MeinFenster muss dann den Konstruktor "public MeinFenster(Logik l)" haben. Die Referenz zum Logik-Interface speicherst du als Instanzvariable und dann kannst du im actionlistener z.B. l.action() aufrufen.
Damit hast du dann die Trennung erreicht.
 
hupfdule hat gesagt.:
Indem du deiner GUI-Klasse eine Referenz auf die Logikklasse mitgibst. Am besten gleich im Konstruktor. Diese kann dann aus dem ActionListener heraus deren test() aufrufen.

Um das noch etwas sauberer zu handhaben (was allerdings nur in größeren Projekten lohnt), könnte die Logikklasse noch ein Interface implementieren und die GUI-Klasse erwartet dann nur eine Implementierung dieses Interfaces. Damit hättest du noch einmal die Abstraktion erhöht.

BTW: Laut Konventino werden Klassen in Java in PascalCase geschrieben. (MeinFenster statt meinfenster)

Meintest Du das so? Funktionieren tut es jedenfalls. Das mit dem Interface werde ich jetzt auch nochmal probieren.
Code:
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class meinfenster extends JFrame implements ActionListener{
    mainclass neu; //<--- neue Zeile
    public meinfenster() {
        this.setSize(300,100);
        this.setLocation(200,200);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        neu = new mainclass(); //<--- neue Zeile
        try {
            jbInit();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void jbInit() throws Exception {
        ibutton1.setText("TestButton");
        ibutton1.addActionListener(this);
        jLabel1.setHorizontalAlignment(SwingConstants.CENTER);
        jLabel1.setHorizontalTextPosition(SwingConstants.CENTER);
        jLabel1.setText("Test");
        this.getContentPane().add(ibutton1, java.awt.BorderLayout.SOUTH);
        this.getContentPane().add(jLabel1, java.awt.BorderLayout.CENTER);
        this.show();
    }

    JButton ibutton1 = new JButton();
    JLabel jLabel1 = new JLabel();
    public void actionPerformed(ActionEvent e) {
        neu.test(); //<--- neue Zeile
}
}

Natürlich musste ich die Methode text() als nicht statisch ändern.
 

KSG9|sebastian

Top Contributor
nein so erzeugst5 du aus der GUI heraus ne neue Logikklasse.
So war es gemeint (wie ich oben schon geschrieben hab)
ICH hat gesagt.:
deine Logik sieht z.B. so aus

Code:
interface Logik{ 
  public void test(); 
  public void ende(); 
  public void action(); 
  // noch mehr methodenkörper 
} 

class LogikImpl implements Logik{ 
   public LogikImpl(){ 
      MeinFenster mf = new MeinFenster(this); 
   } 
   public void action(){ 
      System.out.println("action performed"); 
   } 
   public void test(){ 
      // do something 
   } 
   public void ende(){ 
      System.exit(1); 
   } 
}
Und deine Klasse MeinFenster muss dann den Konstruktor "public MeinFenster(Logik l)" haben. Die Referenz zum Logik-Interface speicherst du als Instanzvariable und dann kannst du im actionlistener z.B. l.action() aufrufen.
Damit hast du dann die Trennung erreicht.
 

hupfdule

Top Contributor
Meintest Du das so?
Nein. Du erzeugt in der GUI einen neuen Controller. Das ist nicht Sinn der Sache. Der Controller soll die GUI erzeugen. Und gleichzeitig teilt er der GUI mit, wer ihr Controller ist:

Code:
public class MeinFenster extends JFrame implements ActionListener{ 
    MainClass controller; //<--- neue Zeile 
    public meinfenster(MainClass controller) {
         this.controller= controller;
         ...
    }
}

Oder halt statt MainClass das entsprechende Interface.

Natürlich musste ich die Methode text() als nicht statisch ändern.
Es gibt aber doch auch keinen Grund, warum diese statisch sein sollte?
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
F Zugriff auf Oberfläche bzw Trennung GUI / Logik AWT, Swing, JavaFX & SWT 3
G Korrekte Trennung von GUI, Logik und Event nach MVC AWT, Swing, JavaFX & SWT 5
O Trennung Gui und Logik - Strukturierte Client Anwendung AWT, Swing, JavaFX & SWT 4
J Saubere Trennung Model, View, Controller Javafx AWT, Swing, JavaFX & SWT 10
D Swing Trennung der UI- und Persistenz-Schicht AWT, Swing, JavaFX & SWT 1
A Trennung GUI und Funktion AWT, Swing, JavaFX & SWT 5
J prinzipielles verständnis für Oberfläche/Code-trennung AWT, Swing, JavaFX & SWT 5
O Trennung GUI / Funktionalität AWT, Swing, JavaFX & SWT 3
D Trennung des Event-Handling von der GUI AWT, Swing, JavaFX & SWT 4
D Trennung von Programm und Oberfläche AWT, Swing, JavaFX & SWT 3
O Trennung Gui und Anwendungslogik AWT, Swing, JavaFX & SWT 13
S Logik auf GUI übertragen AWT, Swing, JavaFX & SWT 2
P Swing GUI noch nicht gezeichnet - Logik läuft - blockiert AWT, Swing, JavaFX & SWT 3
N MVC - Logik zum Verändern der View AWT, Swing, JavaFX & SWT 8
E SWT und Separierung von Logik, Präsentation sowie Modell (also eine Form von MVC) AWT, Swing, JavaFX & SWT 10
O Zugriff auf PreferenceStore aus der Business-Logik-Schicht? AWT, Swing, JavaFX & SWT 11
V Wieviel Logik in paintComponent? AWT, Swing, JavaFX & SWT 7

Ähnliche Java Themen


Oben