+ Antworten
Ergebnis 1 bis 7 von 7

Thema: Wie kann ich eleganter zwischen Logik und grafischer Oberfläche trennen?

  1. #1
    User Halbes Megabyte Themenstarter
    Avatar von Crian
    Registriert seit
    02.08.2013
    Fachbeiträge
    552
    Genannt
    32 Post(s)
    Einleitung

    Ich trenne für meine Projekte mit grafischer Oberfläche gerne die logischen Teile von denen, die sich um die GUI kümmern.

    Dabei entspricht meine Logik wohl dem Controller aus dem MVC-Pattern und stellt damit die Verbindung zwischen den Daten (dem Modell) und der View dar. Er enthält im Normalfall die Daten (die in eigenen Klassen liegen) und eine Verbindung zur Gui.

    Die Gui (entspricht der View aus dem MVC-Pattern) bekommt wiederum die Logik "injiziert" (sprich im Konstruktor übergeben), um in ActionListern von Buttons oder ähnlichem die inhaltliche Arbeit an die Logik zu übergeben.


    Paketstruktur der Beispiele

    Die Struktur der Beispiele in meinem extra für dieses Beispiel erstellte Projekt (was auch die kurzen Paketnamen erklären mag) sieht wie folgt aus:

    • complex
      • logic
      • ui
    • data
    • simple
      • logic
      • ui
    • start



    Daten für die Beispiele

    Als Daten (entspricht dem Model im MVC-Pattern) verwende ich in den Beispielen eine Person mit den folgenden exemplarischen Daten:

    • Vorname
    • Nachname
    • Geburtstag
    • Straße
    • Postleitzahl
    • Ort
    • Land


    Die Klasse data.Person enthält neben dem Konstruktor die Getter und einige Hilfsmethoden, weil ich unveränderliche Objekte mag.
    Off topic:
    Dinge wie equals() und hashCode(), die diese Klassen normalerweise haben, lasse ich hier weg, weil sie in den Beispielen nicht gebraucht werden.

    So sieht sie aus:

    Java Code:
    1. package data;
    2.  
    3. public class Person {
    4.  
    5.     private final String forename;
    6.     private final String surname;
    7.     private final String birthday;
    8.     private final String street;
    9.     private final String postalCode;
    10.     private final String town;
    11.     private final String country;
    12.  
    13.     public Person(String forename, String surname, String birthday,
    14.             String street, String postalCode, String town, String country) {
    15.         this.forename = forename;
    16.         this.surname = surname;
    17.         this.birthday = birthday;
    18.         this.street = street;
    19.         this.postalCode = postalCode;
    20.         this.town = town;
    21.         this.country = country;
    22.     }
    23.  
    24.     public String getForename() {
    25.         return forename;
    26.     }
    27.  
    28.     public String getSurname() {
    29.         return surname;
    30.     }
    31.  
    32.     public String getBirthday() {
    33.         return birthday;
    34.     }
    35.  
    36.     public String getStreet() {
    37.         return street;
    38.     }
    39.  
    40.     public String getPostalCode() {
    41.         return postalCode;
    42.     }
    43.  
    44.     public String getTown() {
    45.         return town;
    46.     }
    47.  
    48.     public String getCountry() {
    49.         return country;
    50.     }
    51.  
    52.     @Override
    53.     public String toString() {
    54.         return "Person [forename=" + forename + ", surname=" + surname
    55.                 + ", birthday=" + birthday + ", street=" + street
    56.                 + ", postalCode=" + postalCode + ", town=" + town
    57.                 + ", country=" + country + "]";
    58.     }
    59.  
    60.     public static Person createWithNewForename(Person person, String forename) {
    61.         return new Person(forename, person.getSurname(), person.getBirthday(),
    62.                 person.getStreet(), person.getPostalCode(), person.getTown(),
    63.                 person.getCountry());
    64.     }
    65.  
    66.     public static Person createWithNewSurname(Person person, String surname) {
    67.         return new Person(person.getForename(), surname, person.getBirthday(),
    68.                 person.getStreet(), person.getPostalCode(), person.getTown(),
    69.                 person.getCountry());
    70.     }
    71.  
    72.     public static Person createWithNewBirthday(Person person, String birthday) {
    73.         return new Person(person.getForename(), person.getSurname(), birthday,
    74.                 person.getStreet(), person.getPostalCode(), person.getTown(),
    75.                 person.getCountry());
    76.     }
    77.  
    78.     public static Person createWithNewStreet(Person person, String street) {
    79.         return new Person(person.getForename(), person.getSurname(),
    80.                 person.getBirthday(), street, person.getPostalCode(),
    81.                 person.getTown(), person.getCountry());
    82.     }
    83.  
    84.     public static Person createWithNewPostalCode(Person person,
    85.             String postalCode) {
    86.         return new Person(person.getForename(), person.getSurname(),
    87.                 person.getBirthday(), person.getStreet(), postalCode,
    88.                 person.getTown(), person.getCountry());
    89.     }
    90.  
    91.     public static Person createWithNewTown(Person person, String town) {
    92.         return new Person(person.getForename(), person.getSurname(),
    93.                 person.getBirthday(), person.getStreet(),
    94.                 person.getPostalCode(), town, person.getCountry());
    95.     }
    96.  
    97.     public static Person createWithNewCountry(Person person, String country) {
    98.         return new Person(person.getForename(), person.getSurname(),
    99.                 person.getBirthday(), person.getStreet(),
    100.                 person.getPostalCode(), person.getTown(), country);
    101.     }
    102.  
    103. }


    Einfaches Beispiel

    Wie kann ich eleganter zwischen Logik und grafischer Oberfläche trennen?-simplegui.png

    Das einfache Beispiel besteht aus einer Logik- und einer Guiklasse sowie einer Klasse, die das ganze startet. Dem Beispielcharakter geschuldet erfolgen die Ausgaben rundherum schlicht auf die Standardausgabe.

    Start des einfachen Beispiels

    Den Startpunkt des einfachen Beispielprogramms bildet die Klasse start.SimpleLogicAndGuiExample:

    Java Code:
    1. package start;
    2.  
    3. import data.Person;
    4. import simple.logic.SimpleLogic;
    5.  
    6. public class SimpleLogicAndGuiExample {
    7.  
    8.     public static void main(String[] args) {
    9.         Person person = new Person("Max", "Mustermann", "01.01.1990",
    10.                 "Musterstraße 123", "12345", "Musterhausen", "Deutschland");
    11.  
    12.         System.out.println("Zu Beginn:\n    " + person);
    13.  
    14.         SimpleLogic logic = new SimpleLogic(person);
    15.         logic.start();
    16.     }
    17.  
    18. }

    Logik des einfachen Beispiels

    Die Logik des einfachen Beispielprogramms bildet die Klasse simple.logic.SimpleLogic:

    Java Code:
    1. package simple.logic;
    2.  
    3. import data.Person;
    4. import simple.ui.SimpleGui;
    5.  
    6. public class SimpleLogic {
    7.  
    8.     private final SimpleGui gui;
    9.  
    10.     private Person person;
    11.  
    12.     public SimpleLogic(final Person person) {
    13.         this.person = person;
    14.         gui = new SimpleGui(this);
    15.     }
    16.  
    17.     public void start() {
    18.         gui.show();
    19.     }
    20.  
    21.     public String getForename() {
    22.         return person.getForename();
    23.     }
    24.  
    25.     public String getSurname() {
    26.         return person.getSurname();
    27.     }
    28.  
    29.     public String getBirthday() {
    30.         return person.getBirthday();
    31.     }
    32.  
    33.     public String getStreet() {
    34.         return person.getStreet();
    35.     }
    36.  
    37.     public String getPostalCode() {
    38.         return person.getPostalCode();
    39.     }
    40.  
    41.     public String getTown() {
    42.         return person.getTown();
    43.     }
    44.  
    45.     public String getCountry() {
    46.         return person.getCountry();
    47.     }
    48.  
    49.     public void setForename(final String forename) {
    50.         person = Person.createWithNewForename(person, forename);
    51.     }
    52.  
    53.     public void setSurname(final String surname) {
    54.         person = Person.createWithNewSurname(person, surname);
    55.     }
    56.  
    57.     public void setBirthday(final String birthday) {
    58.         person = Person.createWithNewBirthday(person, birthday);
    59.     }
    60.  
    61.     public void setStreet(final String street) {
    62.         person = Person.createWithNewStreet(person, street);
    63.     }
    64.  
    65.     public void setPostalCode(final String postalCode) {
    66.         person = Person.createWithNewPostalCode(person, postalCode);
    67.     }
    68.  
    69.     public void setTown(final String town) {
    70.         person = Person.createWithNewTown(person, town);
    71.     }
    72.  
    73.     public void setCountry(final String country) {
    74.         person = Person.createWithNewCountry(person, country);
    75.     }
    76.  
    77.     public void quitPressed() {
    78.         System.out.println("Nach Klick auf Quit:\n    " + person);
    79.         quit();
    80.     }
    81.  
    82.     private void quit() {
    83.         gui.quit();
    84.     }
    85.  
    86.     public void okPressed() {
    87.         System.out.println("Nach Klick auf OK:\n    " + person);
    88.         quit();
    89.     }
    90.  
    91. }

    Oberfläche des einfachen Beispiels

    Die grafische Oberfläche des einfachen Beispielprogramms bildet die Klasse simple.ui.SimpleGui:

    Java Code:
    1. package simple.ui;
    2.  
    3. import java.awt.BorderLayout;
    4. import java.awt.Component;
    5. import java.awt.Dimension;
    6. import java.awt.GridLayout;
    7. import java.awt.event.ActionEvent;
    8. import java.awt.event.ActionListener;
    9.  
    10. import javax.swing.BorderFactory;
    11. import javax.swing.JButton;
    12. import javax.swing.JFrame;
    13. import javax.swing.JLabel;
    14. import javax.swing.JPanel;
    15. import javax.swing.JTextField;
    16. import javax.swing.SwingUtilities;
    17. import javax.swing.UIManager;
    18.  
    19. import simple.logic.SimpleLogic;
    20.  
    21. public class SimpleGui {
    22.  
    23.     private static final int LABEL_WIDTH = 100;
    24.     private static final int FIELD_WIDTH = 300;
    25.     private static final int FIELD_HIGHT = 30;
    26.  
    27.     private final SimpleLogic logic;
    28.  
    29.     private final JFrame frame;
    30.  
    31.     private final JTextField forenameField;
    32.     private final JTextField surnameField;
    33.     private final JTextField birthdayField;
    34.     private final JTextField streetField;
    35.     private final JTextField postalCodeField;
    36.     private final JTextField townField;
    37.     private final JTextField countryField;
    38.  
    39.     public SimpleGui(final SimpleLogic logic) {
    40.         this.logic = logic;
    41.  
    42.         setNiceLayoutManager();
    43.  
    44.         frame = new JFrame();
    45.         forenameField = new JTextField();
    46.         surnameField = new JTextField();
    47.         birthdayField = new JTextField();
    48.         streetField = new JTextField();
    49.         postalCodeField = new JTextField();
    50.         townField = new JTextField();
    51.         countryField = new JTextField();
    52.  
    53.         SwingUtilities.invokeLater(new Runnable() {
    54.             @Override
    55.             public void run() {
    56.                 createGui();
    57.                 loadPersonDataIntoFields();
    58.             }
    59.         });
    60.     }
    61.  
    62.     private static void setNiceLayoutManager() {
    63.         try {
    64.             UIManager.setLookAndFeel(
    65.                     "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
    66.         }
    67.         catch (Exception e) {
    68.             e.printStackTrace();
    69.         }
    70.     }
    71.  
    72.     private void createGui() {
    73.         frame.setTitle("Einfaches Beispiel für Logik und Gui");
    74.         frame.setLayout(new BorderLayout());
    75.  
    76.         frame.add(createAllButton(), BorderLayout.SOUTH);
    77.         frame.add(createDataPart(), BorderLayout.CENTER);
    78.  
    79.         frame.pack();
    80.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    81.     }
    82.  
    83.     private Component createAllButton() {
    84.         JPanel panel = new JPanel();
    85.         panel.setLayout(new BorderLayout());
    86.  
    87.         panel.add(createQuitButton(), BorderLayout.WEST);
    88.         panel.add(createGoodButtons(), BorderLayout.EAST);
    89.  
    90.         return panel;
    91.     }
    92.  
    93.     private Component createGoodButtons() {
    94.         JPanel panel = new JPanel();
    95.         panel.setLayout(new BorderLayout());
    96.  
    97.         panel.add(createApplyButton(), BorderLayout.WEST);
    98.         panel.add(createOkButton(), BorderLayout.EAST);
    99.  
    100.         return panel;
    101.     }
    102.  
    103.     private Component createApplyButton() {
    104.         JButton applyButton = new JButton("Apply");
    105.         applyButton.addActionListener(new ActionListener() {
    106.             @Override
    107.             public void actionPerformed(ActionEvent e) {
    108.                 changePersonData();
    109.             }
    110.         });
    111.         return applyButton;
    112.     }
    113.  
    114.     private Component createOkButton() {
    115.         JButton okButton = new JButton("OK");
    116.         okButton.addActionListener(new ActionListener() {
    117.             @Override
    118.             public void actionPerformed(ActionEvent e) {
    119.                 changePersonData();
    120.                 logic.okPressed();
    121.             }
    122.         });
    123.         return okButton;
    124.     }
    125.  
    126.     private void changePersonData() {
    127.         logic.setForename(forenameField.getText());
    128.         logic.setSurname(surnameField.getText());
    129.         logic.setBirthday(birthdayField.getText());
    130.         logic.setStreet(streetField.getText());
    131.         logic.setPostalCode(postalCodeField.getText());
    132.         logic.setTown(townField.getText());
    133.         logic.setCountry(countryField.getText());
    134.     }
    135.  
    136.     private Component createQuitButton() {
    137.         JButton quitButton = new JButton("Quit");
    138.         quitButton.addActionListener(new ActionListener() {
    139.             @Override
    140.             public void actionPerformed(ActionEvent e) {
    141.                 logic.quitPressed();
    142.             }
    143.         });
    144.         return quitButton;
    145.     }
    146.  
    147.     private Component createDataPart() {
    148.         JPanel panel = new JPanel();
    149.         panel.setLayout(new BorderLayout());
    150.  
    151.         panel.add(createDataButtons(), BorderLayout.EAST);
    152.         panel.add(createDataArea(), BorderLayout.CENTER);
    153.  
    154.         return panel;
    155.     }
    156.  
    157.     private Component createDataArea() {
    158.         JPanel panel = new JPanel();
    159.         panel.setLayout(new GridLayout(0, 1, 5, 5));
    160.         panel.setBorder(BorderFactory.createTitledBorder(""));
    161.  
    162.         panel.add(createFieldPanel("Nachname", forenameField));
    163.         panel.add(createFieldPanel("Vorname", surnameField));
    164.         panel.add(createFieldPanel("Geburtsdatum", birthdayField));
    165.         panel.add(createFieldPanel("Straße", streetField));
    166.         panel.add(createFieldPanel("Postleitzahl", postalCodeField));
    167.         panel.add(createFieldPanel("Ort", townField));
    168.         panel.add(createFieldPanel("Land", countryField));
    169.  
    170.         return panel;
    171.     }
    172.  
    173.     private Component createFieldPanel(String labelText, JTextField field) {
    174.         JPanel panel = new JPanel();
    175.         panel.setLayout(new BorderLayout());
    176.  
    177.         JLabel label = new JLabel(labelText + ":");
    178.  
    179.         label.setPreferredSize(new Dimension(LABEL_WIDTH, FIELD_HIGHT));
    180.         field.setPreferredSize(new Dimension(FIELD_WIDTH, FIELD_HIGHT));
    181.  
    182.         panel.add(label, BorderLayout.WEST);
    183.         panel.add(field, BorderLayout.CENTER);
    184.  
    185.         return panel;
    186.     }
    187.  
    188.     private Component createDataButtons() {
    189.         JPanel panel = new JPanel();
    190.         panel.setLayout(new BorderLayout());
    191.         panel.setBorder(BorderFactory.createTitledBorder(""));
    192.  
    193.         JPanel subpanel = new JPanel();
    194.         subpanel.setLayout(new BorderLayout());
    195.  
    196.         subpanel.add(createClearAllButton(), BorderLayout.NORTH);
    197.         subpanel.add(createReloadButton(), BorderLayout.SOUTH);
    198.         panel.add(subpanel, BorderLayout.NORTH);
    199.  
    200.         return panel;
    201.     }
    202.  
    203.     private Component createClearAllButton() {
    204.         JButton clearAllButton = new JButton("clear");
    205.         clearAllButton.addActionListener(new ActionListener() {
    206.             @Override
    207.             public void actionPerformed(ActionEvent e) {
    208.                 forenameField.setText("");
    209.                 surnameField.setText("");
    210.                 birthdayField.setText("");
    211.                 streetField.setText("");
    212.                 postalCodeField.setText("");
    213.                 townField.setText("");
    214.                 countryField.setText("");
    215.             }
    216.         });
    217.         return clearAllButton;
    218.     }
    219.  
    220.     private Component createReloadButton() {
    221.         JButton reloadButton = new JButton("reload");
    222.         reloadButton.addActionListener(new ActionListener() {
    223.             @Override
    224.             public void actionPerformed(ActionEvent e) {
    225.                 loadPersonDataIntoFields();
    226.             }
    227.         });
    228.         return reloadButton;
    229.     }
    230.  
    231.     private void loadPersonDataIntoFields() {
    232.         forenameField.setText(logic.getForename());
    233.         surnameField.setText(logic.getSurname());
    234.         birthdayField.setText(logic.getBirthday());
    235.         streetField.setText(logic.getStreet());
    236.         postalCodeField.setText(logic.getPostalCode());
    237.         townField.setText(logic.getTown());
    238.         countryField.setText(logic.getCountry());
    239.     }
    240.  
    241.     public void quit() {
    242.         SwingUtilities.invokeLater(new Runnable() {
    243.             @Override
    244.             public void run() {
    245.                 frame.setVisible(false);
    246.                 frame.dispose();
    247.             }
    248.         });
    249.     }
    250.  
    251.     public void show() {
    252.         SwingUtilities.invokeLater(new Runnable() {
    253.             @Override
    254.             public void run() {
    255.                 frame.setVisible(true);
    256.             }
    257.         });
    258.     }
    259.  
    260. }
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken Wie kann ich eleganter zwischen Logik und grafischer Oberfläche trennen?-complexguiwithframe.png   Wie kann ich eleganter zwischen Logik und grafischer Oberfläche trennen?-complexguiwithdialogstart.png   Wie kann ich eleganter zwischen Logik und grafischer Oberfläche trennen?-complexguiwithdialogthedialog.png  
    Geändert von Crian (28.10.2015 um 13:27 Uhr)

  2. #2
    User Halbes Megabyte Themenstarter
    Avatar von Crian
    Registriert seit
    02.08.2013
    Fachbeiträge
    552
    Genannt
    32 Post(s)
    Komplexere Beispiele

    Für den komplexeren Fall zeige ich zwei Anwendungsbeispiele, um die unterschiedlichen Ansprüche an mögliche Lösungen darzustellen:

    • Ein komplexeres Beispiel mit JFrame.
    • Ein komplexeres Beispiel mit JDialog.


    In beiden Fällen wird das obige, einfache Beispiel aufgetrennt in einen PersonPanel und die Umgebung des ganzen, so dass dieses einmal in einem größeren JFrame und einmal innerhalb eines JDialogs aufgerufen wird. In diesem Beispiel macht das vielleicht nicht so schrecklich viel Sinn, in dem Problemfall, zu dem ich hier Fragen stellen wollte, was der Grund für die Erstellung all dieser Beispielklassen war, macht das aber sehr wohl Sinn und wird auch verwendet.

    Off topic:
    In einem echten Projekt hätte ich den doppelten Code in den beiden Beispielen natürlich vermieden. Hier jedoch geht es gerade um die Unterschiede zwischen diesen.

    Die Beispiele zeigen quasi die Entstehungsgeschichte des komplexeren Falles aus dem einfacheren.

    So ist hier auch einfach aus der Bequemlichkeit, für die Vorstellung der Klassen auf eine weitere Hilfsklasse verzichten zu wollen, die Methode setNiceLayoutManager() mehrfach vorhanden.


    Zunächst betrachten wir den PersonPanel, der beiden Beispielen zugrundeliegt. Er besteht aus einer Logik- und einer Gui-Klasse:

    Logik des PersonPanels

    Die Logik des PersonPanels steckt in der Klasse complex.logic.PersonPanelLogic:

    Java Code:
    1. package complex.logic;
    2.  
    3. import javax.swing.JPanel;
    4.  
    5. import complex.ui.PersonPanelGui;
    6.  
    7. import data.Person;
    8.  
    9. public class PersonPanelLogic implements PersonPanelLogicForGui, PersonPanelLogicForExternal {
    10.  
    11.     private final PersonPanelGui gui;
    12.  
    13.     private Person person;
    14.  
    15.     public PersonPanelLogic(final Person person) {
    16.         this.person = person;
    17.         gui = new PersonPanelGui((PersonPanelLogicForGui) this);
    18.     }
    19.  
    20.     @Override
    21.     public JPanel getPersonPanel() {
    22.         return gui.getPersonPanel();
    23.     }
    24.  
    25.     @Override
    26.     public Person getPerson() {
    27.         return person;
    28.     }
    29.  
    30.     @Override
    31.     public void savePersonFromGui() {
    32.         gui.savePersonFromGui();
    33.     }
    34.  
    35.     @Override
    36.     public String getForename() {
    37.         return person.getForename();
    38.     }
    39.  
    40.     @Override
    41.     public String getSurname() {
    42.         return person.getSurname();
    43.     }
    44.  
    45.     @Override
    46.     public String getBirthday() {
    47.         return person.getBirthday();
    48.     }
    49.  
    50.     @Override
    51.     public String getStreet() {
    52.         return person.getStreet();
    53.     }
    54.  
    55.     @Override
    56.     public String getPostalCode() {
    57.         return person.getPostalCode();
    58.     }
    59.  
    60.     @Override
    61.     public String getTown() {
    62.         return person.getTown();
    63.     }
    64.  
    65.     @Override
    66.     public String getCountry() {
    67.         return person.getCountry();
    68.     }
    69.  
    70.     @Override
    71.     public void setForename(final String forename) {
    72.         person = Person.createWithNewForename(person, forename);
    73.     }
    74.  
    75.     @Override
    76.     public void setSurname(final String surname) {
    77.         person = Person.createWithNewSurname(person, surname);
    78.     }
    79.  
    80.     @Override
    81.     public void setBirthday(final String birthday) {
    82.         person = Person.createWithNewBirthday(person, birthday);
    83.     }
    84.  
    85.     @Override
    86.     public void setStreet(final String street) {
    87.         person = Person.createWithNewStreet(person, street);
    88.     }
    89.  
    90.     @Override
    91.     public void setPostalCode(final String postalCode) {
    92.         person = Person.createWithNewPostalCode(person, postalCode);
    93.     }
    94.  
    95.     @Override
    96.     public void setTown(final String town) {
    97.         person = Person.createWithNewTown(person, town);
    98.     }
    99.  
    100.     @Override
    101.     public void setCountry(final String country) {
    102.         person = Person.createWithNewCountry(person, country);
    103.     }
    104.  
    105. }

    Um klar die Methoden der internen und der externen Verwendung zuzuordnen, habe ich zwei Interfaces erstellt:

    • PersonPanelLogicForGui
    • PersonPanelLogicForExternal


    Off topic:
    Die Namen sind ziemlich sicher Murks. Eigentlich sollten Interfaces das allgemeinere und eine Klasse, die dieses implementiert, etwas spezielleres sein, die Namen sollten dies ausdrücken. Aber die lassen sich immer noch ändern.

    Falls jemand hierzu auch eine gute Idee hat, nur her damit.


    Wenig überraschender Weise sehen diese so aus:

    Interface complex.PersonPanelLogicForExternal:

    Java Code:
    1. package complex.logic;
    2.  
    3. import javax.swing.JPanel;
    4.  
    5. import data.Person;
    6.  
    7. public interface PersonPanelLogicForExternal {
    8.  
    9.     JPanel getPersonPanel();
    10.  
    11.     Person getPerson();
    12.  
    13.     void savePersonFromGui();
    14.  
    15. }

    Interface complex.PersonPanelLogicForGui:

    Java Code:
    1. package complex.logic;
    2.  
    3. public interface PersonPanelLogicForGui {
    4.  
    5.     String getForename();
    6.  
    7.     String getSurname();
    8.  
    9.     String getBirthday();
    10.  
    11.     String getStreet();
    12.  
    13.     String getPostalCode();
    14.  
    15.     String getTown();
    16.  
    17.     String getCountry();
    18.  
    19.     void setForename(String forename);
    20.  
    21.     void setSurname(String surname);
    22.  
    23.     void setBirthday(String birthday);
    24.  
    25.     void setStreet(String street);
    26.  
    27.     void setPostalCode(String postalCode);
    28.  
    29.     void setTown(String town);
    30.  
    31.     void setCountry(String country);
    32.  
    33. }

    Oberfläche des PersonPanels

    Die grafische Oberfläche des PersonPanels steckt in der Klasse complex.ui.PersonPanelGui:

    Java Code:
    1. package complex.ui;
    2.  
    3. import java.awt.BorderLayout;
    4. import java.awt.Component;
    5. import java.awt.Dimension;
    6. import java.awt.GridLayout;
    7. import java.awt.event.ActionEvent;
    8. import java.awt.event.ActionListener;
    9.  
    10. import javax.swing.BorderFactory;
    11. import javax.swing.JButton;
    12. import javax.swing.JLabel;
    13. import javax.swing.JPanel;
    14. import javax.swing.JTextField;
    15. import javax.swing.SwingUtilities;
    16.  
    17. import complex.logic.PersonPanelLogicForGui;
    18.  
    19. public class PersonPanelGui {
    20.  
    21.     private static final int LABEL_WIDTH = 100;
    22.     private static final int FIELD_WIDTH = 300;
    23.     private static final int FIELD_HIGHT = 30;
    24.  
    25.     private final PersonPanelLogicForGui logic;
    26.  
    27.     private final JPanel personPanel;
    28.  
    29.     private final JTextField forenameField;
    30.     private final JTextField surnameField;
    31.     private final JTextField birthdayField;
    32.     private final JTextField streetField;
    33.     private final JTextField postalCodeField;
    34.     private final JTextField townField;
    35.     private final JTextField countryField;
    36.  
    37.     public PersonPanelGui(final PersonPanelLogicForGui logic) {
    38.         this.logic = logic;
    39.  
    40.         personPanel = new JPanel();
    41.         forenameField = new JTextField();
    42.         surnameField = new JTextField();
    43.         birthdayField = new JTextField();
    44.         streetField = new JTextField();
    45.         postalCodeField = new JTextField();
    46.         townField = new JTextField();
    47.         countryField = new JTextField();
    48.  
    49.         SwingUtilities.invokeLater(new Runnable() {
    50.             @Override
    51.             public void run() {
    52.                 createGui();
    53.                 loadPersonDataIntoFields();
    54.             }
    55.         });
    56.     }
    57.  
    58.     private void createGui() {
    59.         personPanel.setLayout(new BorderLayout());
    60.  
    61.         personPanel.add(createDataButtons(), BorderLayout.EAST);
    62.         personPanel.add(createDataArea(), BorderLayout.CENTER);
    63.     }
    64.  
    65.     private Component createDataArea() {
    66.         JPanel panel = new JPanel();
    67.         panel.setLayout(new GridLayout(0, 1, 5, 5));
    68.         panel.setBorder(BorderFactory.createTitledBorder(""));
    69.  
    70.         panel.add(createFieldPanel("Nachname", forenameField));
    71.         panel.add(createFieldPanel("Vorname", surnameField));
    72.         panel.add(createFieldPanel("Geburtsdatum", birthdayField));
    73.         panel.add(createFieldPanel("Straße", streetField));
    74.         panel.add(createFieldPanel("Postleitzahl", postalCodeField));
    75.         panel.add(createFieldPanel("Ort", townField));
    76.         panel.add(createFieldPanel("Land", countryField));
    77.  
    78.         return panel;
    79.     }
    80.  
    81.     private Component createFieldPanel(String labelText, JTextField field) {
    82.         JPanel panel = new JPanel();
    83.         panel.setLayout(new BorderLayout());
    84.  
    85.         JLabel label = new JLabel(labelText + ":");
    86.  
    87.         label.setPreferredSize(new Dimension(LABEL_WIDTH, FIELD_HIGHT));
    88.         field.setPreferredSize(new Dimension(FIELD_WIDTH, FIELD_HIGHT));
    89.  
    90.         panel.add(label, BorderLayout.WEST);
    91.         panel.add(field, BorderLayout.CENTER);
    92.  
    93.         return panel;
    94.     }
    95.  
    96.     private Component createDataButtons() {
    97.         JPanel panel = new JPanel();
    98.         panel.setLayout(new BorderLayout());
    99.         panel.setBorder(BorderFactory.createTitledBorder(""));
    100.  
    101.         JPanel subpanel = new JPanel();
    102.         subpanel.setLayout(new BorderLayout());
    103.  
    104.         subpanel.add(createClearAllButton(), BorderLayout.NORTH);
    105.         subpanel.add(createReloadButton(), BorderLayout.SOUTH);
    106.         panel.add(subpanel, BorderLayout.NORTH);
    107.  
    108.         panel.add(createSaveButton(), BorderLayout.SOUTH);
    109.  
    110.         return panel;
    111.     }
    112.  
    113.     private Component createClearAllButton() {
    114.         JButton clearAllButton = new JButton("clear");
    115.         clearAllButton.addActionListener(new ActionListener() {
    116.             @Override
    117.             public void actionPerformed(ActionEvent e) {
    118.                 forenameField.setText("");
    119.                 surnameField.setText("");
    120.                 birthdayField.setText("");
    121.                 streetField.setText("");
    122.                 postalCodeField.setText("");
    123.                 townField.setText("");
    124.                 countryField.setText("");
    125.             }
    126.         });
    127.         return clearAllButton;
    128.     }
    129.  
    130.     private Component createReloadButton() {
    131.         JButton reloadButton = new JButton("reload");
    132.         reloadButton.addActionListener(new ActionListener() {
    133.             @Override
    134.             public void actionPerformed(ActionEvent e) {
    135.                 loadPersonDataIntoFields();
    136.             }
    137.         });
    138.         return reloadButton;
    139.     }
    140.  
    141.     private void loadPersonDataIntoFields() {
    142.         forenameField.setText(logic.getForename());
    143.         surnameField.setText(logic.getSurname());
    144.         birthdayField.setText(logic.getBirthday());
    145.         streetField.setText(logic.getStreet());
    146.         postalCodeField.setText(logic.getPostalCode());
    147.         townField.setText(logic.getTown());
    148.         countryField.setText(logic.getCountry());
    149.     }
    150.  
    151.     private Component createSaveButton() {
    152.         JButton okButton = new JButton("Save");
    153.         okButton.addActionListener(new ActionListener() {
    154.             @Override
    155.             public void actionPerformed(ActionEvent e) {
    156.                 changePersonData();
    157.             }
    158.         });
    159.         return okButton;
    160.     }
    161.  
    162.     private void changePersonData() {
    163.         logic.setForename(forenameField.getText());
    164.         logic.setSurname(surnameField.getText());
    165.         logic.setBirthday(birthdayField.getText());
    166.         logic.setStreet(streetField.getText());
    167.         logic.setPostalCode(postalCodeField.getText());
    168.         logic.setTown(townField.getText());
    169.         logic.setCountry(countryField.getText());
    170.     }
    171.  
    172.     public void savePersonFromGui() {
    173.         changePersonData();
    174.     }
    175.  
    176.     public JPanel getPersonPanel() {
    177.         return personPanel;
    178.     }
    179.  
    180. }


    Komplexeres Beispiel mit JFrame

    Wie kann ich eleganter zwischen Logik und grafischer Oberfläche trennen?-complexguiwithframe.png

    Hier wird der PersonPanel innerhalb eines größeren Frames als ein Element eingebettet.

    Start des komplexeren Beispiels mit JFrame

    Den Startpunkt des komplexeren Beispielprogramms mit JFrame bildet die Klasse complex.ComplexLogicAndGuiExampleWithFrame:

    Java Code:
    1. package start;
    2.  
    3. import complex.logic.PersonFrameLogic;
    4.  
    5. import data.Person;
    6.  
    7. public class ComplexLogicAndGuiExampleWithFrame {
    8.  
    9.     public static void main(String[] args) {
    10.         Person person = new Person("Max", "Mustermann", "01.01.1990",
    11.                 "Musterstraße 123", "12345", "Musterhausen", "Deutschland");
    12.  
    13.         System.out.println("Zu Beginn:\n    " + person);
    14.  
    15.         PersonFrameLogic logic = new PersonFrameLogic(person);
    16.         logic.start();
    17.     }
    18.  
    19. }

    Logik des komplexeren Beispiels mit JFrame

    Die Logik des komplexeren Beispielprogramms mit JFrame bildet die Klasse complex.logic.PersonFrameLogic:

    Java Code:
    1. package complex.logic;
    2.  
    3. import javax.swing.JPanel;
    4.  
    5. import complex.ui.PersonFrameGui;
    6.  
    7. import data.Person;
    8.  
    9. public class PersonFrameLogic {
    10.  
    11.     private final PersonPanelLogicForExternal personLogic;
    12.     private final PersonFrameGui gui;
    13.  
    14.     public PersonFrameLogic(Person person) {
    15.         personLogic = new PersonPanelLogic(person);
    16.         gui = new PersonFrameGui(this);
    17.     }
    18.  
    19.     public void start() {
    20.         gui.show();
    21.     }
    22.  
    23.     public JPanel getPersonPanel() {
    24.         return personLogic.getPersonPanel();
    25.     }
    26.  
    27.     public void okPressed() {
    28.         personLogic.savePersonFromGui();
    29.         System.out.println("Nach Klick auf Ok:\n    " + personLogic.getPerson());
    30.         quit();
    31.     }
    32.  
    33.     public void quitPressed() {
    34.         System.out.println("Nach Klick auf Quit:\n    " + personLogic.getPerson());
    35.         quit();
    36.     }
    37.  
    38.     private void quit() {
    39.         gui.quit();
    40.     }
    41.  
    42. }

    Oberfläche des komplexeren Beispiels mit JFrame

    Die grafische Oberfläche des komplexeren Beispielprogramms mit JFrame bildet die Klasse complex.ui.PersonFrameGui:

    Java Code:
    1. package complex.ui;
    2.  
    3. import java.awt.BorderLayout;
    4. import java.awt.Component;
    5. import java.awt.GridLayout;
    6. import java.awt.event.ActionEvent;
    7. import java.awt.event.ActionListener;
    8.  
    9. import javax.swing.BorderFactory;
    10. import javax.swing.JButton;
    11. import javax.swing.JFrame;
    12. import javax.swing.JLabel;
    13. import javax.swing.JPanel;
    14. import javax.swing.SwingUtilities;
    15. import javax.swing.UIManager;
    16.  
    17. import complex.logic.PersonFrameLogic;
    18.  
    19. public class PersonFrameGui {
    20.  
    21.     private final PersonFrameLogic logic;
    22.  
    23.     private final JFrame frame;
    24.  
    25.     public PersonFrameGui(final PersonFrameLogic logic) {
    26.         this.logic = logic;
    27.  
    28.         setNiceLayoutManager();
    29.  
    30.         frame = new JFrame();
    31.  
    32.         SwingUtilities.invokeLater(new Runnable() {
    33.             @Override
    34.             public void run() {
    35.                 createGui();
    36.             }
    37.         });
    38.     }
    39.  
    40.     private static void setNiceLayoutManager() {
    41.         try {
    42.             UIManager.setLookAndFeel(
    43.                     "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
    44.         }
    45.         catch (Exception e) {
    46.             e.printStackTrace();
    47.         }
    48.     }
    49.  
    50.     private void createGui() {
    51.         frame.setTitle("Komplexes Beispiel für Logik und Gui mit JFrame");
    52.         frame.setLayout(new BorderLayout());
    53.  
    54.         frame.add(createAllButton(), BorderLayout.SOUTH);
    55.         frame.add(createCenterPart(), BorderLayout.CENTER);
    56.  
    57.         frame.pack();
    58.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    59.     }
    60.  
    61.     private Component createCenterPart() {
    62.         JPanel panel = new JPanel();
    63.         panel.setLayout(new GridLayout(3, 3, 5, 5));
    64.         //panel.setBorder(BorderFactory.createTitledBorder(""));
    65.  
    66.         panel.add(createLabel());
    67.         panel.add(createLabel());
    68.         panel.add(createLabel());
    69.  
    70.         panel.add(createLabel());
    71.         panel.add(createPersonPart());
    72.         panel.add(createLabel());
    73.  
    74.         panel.add(createLabel());
    75.         panel.add(createLabel());
    76.         panel.add(createLabel());
    77.  
    78.         return panel;
    79.     }
    80.  
    81.     private Component createLabel() {
    82.         JLabel label = new JLabel("<html>Hier ist nichts<br>zu sehen, bitte "
    83.                 + "gehen<br>Sie weiter!<html>");
    84.         label.setBorder(BorderFactory.createTitledBorder(""));
    85.         label.setHorizontalAlignment(JLabel.CENTER);
    86.         return label;
    87.     }
    88.  
    89.     private Component createPersonPart() {
    90.         JPanel personPanel = logic.getPersonPanel();
    91.         personPanel.setBorder(BorderFactory.createTitledBorder(""));
    92.         return personPanel;
    93.     }
    94.  
    95.     private Component createAllButton() {
    96.         JPanel panel = new JPanel();
    97.         panel.setLayout(new BorderLayout());
    98.  
    99.         panel.add(createQuitButton(), BorderLayout.WEST);
    100.         panel.add(createOkButton(), BorderLayout.EAST);
    101.  
    102.         return panel;
    103.     }
    104.  
    105.     private Component createOkButton() {
    106.         JButton okButton = new JButton("OK");
    107.         okButton.addActionListener(new ActionListener() {
    108.             @Override
    109.             public void actionPerformed(ActionEvent e) {
    110.                 logic.okPressed();
    111.             }
    112.         });
    113.         return okButton;
    114.     }
    115.  
    116.     private Component createQuitButton() {
    117.         JButton quitButton = new JButton("Quit");
    118.         quitButton.addActionListener(new ActionListener() {
    119.             @Override
    120.             public void actionPerformed(ActionEvent e) {
    121.                 logic.quitPressed();
    122.             }
    123.         });
    124.         return quitButton;
    125.     }
    126.  
    127.  
    128.     public void quit() {
    129.         SwingUtilities.invokeLater(new Runnable() {
    130.             @Override
    131.             public void run() {
    132.                 frame.setVisible(false);
    133.                 frame.dispose();
    134.             }
    135.         });
    136.     }
    137.  
    138.     public void show() {
    139.         SwingUtilities.invokeLater(new Runnable() {
    140.             @Override
    141.             public void run() {
    142.                 frame.setVisible(true);
    143.             }
    144.         });
    145.     }
    146.  
    147. }


    Komplexeres Beispiel mit JDialog

    Wie kann ich eleganter zwischen Logik und grafischer Oberfläche trennen?-complexguiwithdialogstart.png Wie kann ich eleganter zwischen Logik und grafischer Oberfläche trennen?-complexguiwithdialogthedialog.png

    Hier wird der PersonPanel innerhalb eines Dialoges eingebettet, der in einer Oberfläche auf Knopfdruck gestartet wird.

    Start des komplexeren Beispiels mit JDialog

    Der Start des komplexeren Beispiels mit JDialog steckt in der Klasse start.ComplexLogicAndGuiExampleWithDialog:

    Java Code:
    1. package start;
    2.  
    3. import complex.ui.AProgramWithADialogLogic;
    4.  
    5. public class ComplexLogicAndGuiExampleWithDialog {
    6.  
    7.     public static void main(String[] args) {
    8.         AProgramWithADialogLogic logic = new AProgramWithADialogLogic();
    9.         logic.start();
    10.     }
    11.  
    12. }

    Logik des komplexeren Beispiels mit JDialog

    Die Logik des Rahmenprogramms des komplexeren Beispiels mit JDialog steckt in der Klasse complex.logic.AProgramWithADialogLogic:

    Java Code:
    1. package complex.logic;
    2.  
    3. import complex.ui.AProgramWithADialogGui;
    4.  
    5. public class AProgramWithADialogLogic {
    6.  
    7.     private final AProgramWithADialogGui gui;
    8.  
    9.     public AProgramWithADialogLogic() {
    10.         gui = new AProgramWithADialogGui();
    11.     }
    12.  
    13.     public void start() {
    14.         gui.show();
    15.     }
    16.  
    17. }

    Die Logik des Dialoges des komplexeren Beispiels mit JDialog steckt in der Klasse complex.logic.PersonDialogLogic:

    Java Code:
    1. package complex.logic;
    2.  
    3. import java.awt.Point;
    4.  
    5. import javax.swing.JPanel;
    6.  
    7. import complex.ui.PersonDialogGui;
    8. import data.Person;
    9.  
    10. public class PersonDialogLogic {
    11.  
    12.     private final PersonPanelLogicForExternal personLogic;
    13.     private final PersonDialogGui gui;
    14.  
    15.     public PersonDialogLogic(final Point parentPosition) {
    16.         personLogic = new PersonPanelLogic(initPerson());
    17.         gui = new PersonDialogGui(this, parentPosition);
    18.     }
    19.  
    20.     private static Person initPerson() {
    21.         Person person = new Person("Max", "Mustermann", "01.01.1990",
    22.                 "Musterstraße 123", "12345", "Musterhausen", "Deutschland");
    23.         System.out.println("Zu Beginn:\n    " + person);
    24.         return person;
    25.     }
    26.  
    27.     public void start() {
    28.         gui.show();
    29.     }
    30.  
    31.     public JPanel getPersonPanel() {
    32.         return personLogic.getPersonPanel();
    33.     }
    34.  
    35.     public void okPressed() {
    36.         savePersonFromGui();
    37.         System.out.println("Nach Klick auf Ok:\n    " + personLogic.getPerson());
    38.         quit();
    39.     }
    40.  
    41.     public void savePersonFromGui() {
    42.         personLogic.savePersonFromGui();
    43.     }
    44.  
    45.     public void quitPressed() {
    46.         System.out.println("Nach Klick auf Quit:\n    " + personLogic.getPerson());
    47.         quit();
    48.     }
    49.  
    50.     private void quit() {
    51.         gui.quit();
    52.     }
    53.  
    54. }


    Oberfläche des komplexeren Beispiels mit JDialog

    Die grafische Oberfläche des Rahmenprogramms des komplexeren Beispiels mit JDialog steckt in der Klasse complex.ui.AProgramWithADialogGui:

    Java Code:
    1. package complex.ui;
    2.  
    3. import java.awt.BorderLayout;
    4. import java.awt.Component;
    5. import java.awt.GridLayout;
    6. import java.awt.Point;
    7. import java.awt.event.ActionEvent;
    8. import java.awt.event.ActionListener;
    9.  
    10. import javax.swing.BorderFactory;
    11. import javax.swing.JButton;
    12. import javax.swing.JFrame;
    13. import javax.swing.JLabel;
    14. import javax.swing.JPanel;
    15. import javax.swing.SwingUtilities;
    16. import javax.swing.UIManager;
    17.  
    18. import complex.logic.PersonDialogLogic;
    19.  
    20. public class AProgramWithADialogGui {
    21.  
    22.     private final JFrame frame;
    23.  
    24.     public AProgramWithADialogGui() {
    25.         setNiceLayoutManager();
    26.  
    27.         frame = new JFrame();
    28.  
    29.         SwingUtilities.invokeLater(new Runnable() {
    30.             @Override
    31.             public void run() {
    32.                 createGui();
    33.             }
    34.         });
    35.     }
    36.  
    37.     private static void setNiceLayoutManager() {
    38.         try {
    39.             UIManager.setLookAndFeel(
    40.                     "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
    41.         }
    42.         catch (Exception e) {
    43.             e.printStackTrace();
    44.         }
    45.     }
    46.  
    47.     private void createGui() {
    48.         frame.setTitle("Komplexes Beispiel für Logik und Gui mit JDialog");
    49.         frame.setLayout(new BorderLayout());
    50.  
    51.         // TODO : Frame mit Button, der wiederum Dialog startet...
    52.  
    53.         frame.add(createCenterPart(), BorderLayout.CENTER);
    54.  
    55.         frame.pack();
    56.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    57.     }
    58.  
    59.     private Component createCenterPart() {
    60.         JPanel panel = new JPanel();
    61.         panel.setLayout(new GridLayout(3, 3, 5, 5));
    62.         //panel.setBorder(BorderFactory.createTitledBorder(""));
    63.  
    64.         panel.add(createLabel());
    65.         panel.add(createLabel());
    66.         panel.add(createLabel());
    67.  
    68.         panel.add(createLabel());
    69.         panel.add(createShowDialogButton());
    70.         panel.add(createLabel());
    71.  
    72.         panel.add(createLabel());
    73.         panel.add(createLabel());
    74.         panel.add(createLabel());
    75.  
    76.         return panel;
    77.     }
    78.  
    79.     private Component createLabel() {
    80.         JLabel label = new JLabel("<html>Hier ist nichts<br>zu sehen, bitte "
    81.                 + "gehen<br>Sie weiter!<html>");
    82.         label.setBorder(BorderFactory.createTitledBorder(""));
    83.         label.setHorizontalAlignment(JLabel.CENTER);
    84.         return label;
    85.     }
    86.  
    87.     private Component createShowDialogButton() {
    88.         JButton dialogButon = new JButton("Bearbeite Personendaten");
    89.         dialogButon.addActionListener(new ActionListener() {
    90.  
    91.             @Override
    92.             public void actionPerformed(ActionEvent e) {
    93.                 Point parentPosition = frame.getLocation();
    94.                 PersonDialogLogic personLogic = new PersonDialogLogic(parentPosition);
    95.                 personLogic.start();
    96.             }
    97.         });
    98.  
    99.         return dialogButon;
    100.     }
    101.  
    102.     public void show() {
    103.         frame.setVisible(true);
    104.     }
    105.  
    106. }

    Die grafische Oberfläche des Dialogs des komplexeren Beispiels mit JDialog steckt in der Klasse complex.ui.PersonDialogGui:

    Java Code:
    1. package complex.ui;
    2.  
    3. import java.awt.BorderLayout;
    4. import java.awt.Component;
    5. import java.awt.Dialog;
    6. import java.awt.Point;
    7. import java.awt.event.ActionEvent;
    8. import java.awt.event.ActionListener;
    9.  
    10. import javax.swing.BorderFactory;
    11. import javax.swing.JButton;
    12. import javax.swing.JDialog;
    13. import javax.swing.JFrame;
    14. import javax.swing.JPanel;
    15. import javax.swing.SwingUtilities;
    16.  
    17. import complex.logic.PersonDialogLogic;
    18.  
    19. public class PersonDialogGui {
    20.  
    21.     private final PersonDialogLogic logic;
    22.  
    23.     private final JDialog dialog;
    24.  
    25.     public PersonDialogGui(final PersonDialogLogic logic,
    26.             final Point parentPosition) {
    27.         this.logic = logic;
    28.  
    29.         dialog = new JDialog();
    30.  
    31.         SwingUtilities.invokeLater(new Runnable() {
    32.             @Override
    33.             public void run() {
    34.                 createGui(parentPosition);
    35.             }
    36.         });
    37.     }
    38.  
    39.     private void createGui(final Point parentPosition) {
    40.         dialog.setTitle("Komplexes Beispiel für Logik und Gui mit JDialog - der Dialog");
    41.         dialog.setLayout(new BorderLayout());
    42.  
    43.         dialog.add(createAllButton(), BorderLayout.SOUTH);
    44.         dialog.add(createPersonPart(), BorderLayout.CENTER);
    45.  
    46.         dialog.pack();
    47.         dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    48.         dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
    49.  
    50.         int parentX = (int) parentPosition.getX();
    51.         int parentY = (int) parentPosition.getY();
    52.         dialog.setLocation(new Point(parentX + 200, parentY + 120));
    53.     }
    54.  
    55.     private Component createAllButton() {
    56.         JPanel panel = new JPanel();
    57.         panel.setLayout(new BorderLayout());
    58.  
    59.         panel.add(createQuitButton(), BorderLayout.WEST);
    60.         panel.add(createGoodButtons(), BorderLayout.EAST);
    61.  
    62.         return panel;
    63.     }
    64.  
    65.     private Component createGoodButtons() {
    66.         JPanel panel = new JPanel();
    67.         panel.setLayout(new BorderLayout());
    68.  
    69.         panel.add(createApplyButton(), BorderLayout.WEST);
    70.         panel.add(createOkButton(), BorderLayout.EAST);
    71.  
    72.         return panel;
    73.     }
    74.  
    75.     private Component createApplyButton() {
    76.         JButton applyButton = new JButton("Apply");
    77.         applyButton.addActionListener(new ActionListener() {
    78.             @Override
    79.             public void actionPerformed(ActionEvent e) {
    80.                 changePersonData();
    81.             }
    82.         });
    83.         return applyButton;
    84.     }
    85.  
    86.     private Component createOkButton() {
    87.         JButton okButton = new JButton("OK");
    88.         okButton.addActionListener(new ActionListener() {
    89.             @Override
    90.             public void actionPerformed(ActionEvent e) {
    91.                 changePersonData();
    92.                 logic.okPressed();
    93.             }
    94.         });
    95.         return okButton;
    96.     }
    97.  
    98.     private void changePersonData() {
    99.         logic.savePersonFromGui();
    100.     }
    101.  
    102.     private Component createQuitButton() {
    103.         JButton quitButton = new JButton("Quit");
    104.         quitButton.addActionListener(new ActionListener() {
    105.             @Override
    106.             public void actionPerformed(ActionEvent e) {
    107.                 logic.quitPressed();
    108.             }
    109.         });
    110.         return quitButton;
    111.     }
    112.  
    113.     private Component createPersonPart() {
    114.         JPanel personPanel = logic.getPersonPanel();
    115.         personPanel.setBorder(BorderFactory.createTitledBorder(""));
    116.         return personPanel;
    117.     }
    118.  
    119.     public void quit() {
    120.         SwingUtilities.invokeLater(new Runnable() {
    121.             @Override
    122.             public void run() {
    123.                 dialog.setVisible(false);
    124.                 dialog.dispose();
    125.             }
    126.         });
    127.     }
    128.  
    129.     public void show() {
    130.         SwingUtilities.invokeLater(new Runnable() {
    131.             @Override
    132.             public void run() {
    133.                 dialog.setVisible(true);
    134.             }
    135.         });
    136.     }
    137.  
    138. }


    Fragestellung

    Neben dem grundsätzlichen Problem, ob die Logik die wichtigere ist oder die grafische Oberfläche, also welche zuerst erzeugt werden sollte und dann das Gegenstück erzeugt, stellt sich im wesentlichen das folgende Problem:

    Wie kann ich hier noch Logik und Gui sauber trennen?

    Reicht die gezeigte Trennung vielleicht völlig aus?

    Mich stört, dass die PersonLogic das Panel mit den angezeigten Personendaten an die anderen Logiken weiterreichen muss, damit diese es wiederum ihrer Gui übergeben. Irgendwie ist mir da zu viel Gui-Interna in den Logikklassen. Oder stelle ich mich da nur an, um es salopp auszudrücken?

    Konkret stört mich soetwas wie import javax.swing.JPanel; in einer Logikklasse.


    Ferner lässt sich vielleicht das Zusammenspiel der verschiedenen Logiken und Gui-Klassen noch verbessern, gefühlsmäßig ist es holzig. In der Regel ein Indiz, dass es besser geht, eventuell gar völlig anders.

    Off topic:
    Die erste Frage habe ich für mich so beantwortet, dass die Logik die wichtigere Klasse ist, die von außen aufgerufen wird und dann die grafische Oberfläche erzeugt.


    Die Kopplung am Beispiel des Falles mit Dialog genauer betrachtet

    In complex.ui.PersonDialogGui in der Methode createPersonPart():

    Java Code:
    1.     private Component createPersonPart() {
    2.         JPanel personPanel = logic.getPersonPanel();
    3.         personPanel.setBorder(BorderFactory.createTitledBorder(""));
    4.         return personPanel;
    5.     }

    In complex.logic.PersonDialogLogic in der Methode getPersonPanel():

    Java Code:
    1.     public JPanel getPersonPanel() {
    2.         return personLogic.getPersonPanel();
    3.     }

    In complex.logic.PersonPanelLogic in der Methode getPersonPanel():

    Java Code:
    1.     public JPanel getPersonPanel() {
    2.         return gui.getPersonPanel();
    3.     }

    In complex.ui.PersonPanelGui in der Methode getPersonPanel():

    Java Code:
    1.     public JPanel getPersonPanel() {
    2.         return personPanel;
    3.     }


    Lösungsansätze

    • logic.getGui().getPersonPanel() Dann wiederum muss die äußere Gui die innere kennen, was eigentlich überhaupt nicht Not tut, weil es völlig ausreicht, nur das eine Panel zu kennen, das eingebettet werden soll.
    • Mit der Verwendung eines Interfaces, das die Gui versteckt, etwa PersonPanelGetter kann dem abgeholfen werden. Dann hätten wir: logic.getPanelGetter().getPanel() und jede Ebene muss nicht mehr kennen, als sie es bisher tut (kein Import eines JPanel in einer Logikklasse), die Interna werden nicht nach außen enthüllt und dennoch kommt die Klasse, die drankommen muss, von außen an das Panel zur Person.





    Off topic:
    Ich hoffe, ich habe den Sachverhalt umfassend und klar dargestellt. Es hat ziemlich viel Zeit gekostet, aber schon dabei ist mir allerhand klar geworden, was in einer so relativ einfachen Struktur handlicher zu verbessern ist, als an einem (noch) komplexeren, realen Programm.
    Geändert von Crian (28.10.2015 um 13:30 Uhr)

  3. #3
    Global Moderator Viertel Gigabyte Avatar von SlaterB
    Registriert seit
    06.08.2008
    Fachbeiträge
    2.716
    Genannt
    291 Post(s)
    in einem Programm mit Klassen wie PersonFrameLogic und PersonPanelLogic eine Variable personLogic zu nennen ist ungünstig ungenau

    Zitat Zitat von Crian Beitrag anzeigen
    Mich stört, dass die PersonLogicdas Panel mit den angezeigten Personendaten an die anderen Logiken weiterreichen muss
    treibt es da noch auf die Spitze, es gibt weder Klasse noch Interface PersonLogic..

    aber ok, PersonPanelLogic ist die zentrale 'Logic'-Klasse, Panel sogar schon im Namen, abgesehen von dem aber nicht viel mit GUI am Hut,
    Name PersonLogic wäre durchaus auch wieder angemessen,
    dein Zitat vielleicht irgendwas von Freud , unterbewußt bessere Ansicht der Dinge

    dramatisch ist die Kopplung nicht, irgendwer muss nunmal den Überblick haben,
    wobei ich dir zustimme, dass die besser benannte PersonLogic besser vom Panel frei wäre,
    sollte genauso mit Textprogramm, Webauftritt, AWT oder SWK, Eclipse-Plugin usw. funktionieren

    aber die Frage bleibt, irgendwer muss alles zusammenführen, da ist ein Aufbau aus dem Stehgreif eher müßig,
    innerhalb der GUI-Schicht oben drauf sollte es gewiss eine zentrale 'ich weiß wo's langgeht'-Komponente geben, die
    - alle benötigten Logiken kennt/ ggfs. erzeugt oder übergeben bekommt,
    - alle GUI-Bausteine kennt/ wahrscheinlich erzeugt, untereinander bekannt macht

    ob man die dann nun Logic nennt oder was auch immer.., sei es die Logic der GUI-Ebene
    Hansa wird Meister

  4. #4
    User Halbes Megabyte Themenstarter
    Avatar von Crian
    Registriert seit
    02.08.2013
    Fachbeiträge
    552
    Genannt
    32 Post(s)
    Stimmt, ich hatte die Klasse PersonLogic in PersonPanelLogic umbenannt, es bei den Variablen aber vergessen. Guter Tipp!

    Ändern kann ich es oben nun nicht mehr, aber egal.

  5. #5
    User Kilobyte
    Registriert seit
    13.10.2015
    Fachbeiträge
    175
    Genannt
    19 Post(s)
    Welche Aufgabe soll denn die Anwendung überhaupt übernehmen?
    Was ist ein Anwendungsfall der abgedeckt werden soll?

    Das ist das erste worüber man sich klar werden sollte.
    Die Anwendung oder besser gesagt die Architektur sollte genau das wiederspiegeln.
    Das waren keine rhetorischen Fragen.


    Dependency Injection, Inversion of Control sind nun zwei wichtige Stichworte.

    Im Gegensatz zu Swing hat SWT einen nicht zu vernachlässigenden Punkt besser gelöst.
    Jede Komponente muss im Konstruktor ihren Parent erhalten auf dem es gezeichnet wird.
    Damit vereinfacht sich das Problem, ob in einem JFrame einem JPanel oder auf einem JDialog gezeichnet, da auf einem "Renderer" lediglich ein anderer Parent übergeben wird.

    JavaFX mit fxml ist auch empfehlenswert, da es eine sehr gute Aufteilung von Haus aus mitbringt.
    Die View nur in fxml deklariert, kann programmatisch so gut wie nichts außer Darstellen und verweist für alles andere auf einen Controller.

    Der Controller wird automatisch zu jeder View initialisiert und erhält Zugriff auf alle nach außen hin sichtbaren Komponenten und bietet Callbacks für alle Buttons.

    Pseudocode
    Java Code:
    1. View view = new View("view.fxml");
    2. Controller controller = view.getController();
    3. controller.setLogic(logic);
    4. controller.setData(...);
    5.  
    6. Scene scene = new Scene(view);
    7.  
    8. stage.setScene(scene);
    9. // oder
    10. dialog.setScene(scene)
    11. ...
    12.  
    13.  
    14. class Controller {
    15.  
    16.   @FXML
    17.   TextField input;
    18.  
    19.   Logic logic;
    20.  
    21.   void setLogic(Logic logic) {
    22.     this.logic = logic;
    23.   }
    24.   ...
    25.  
    26.   @FXML
    27.   public void btnClick() {
    28.     String txt = input.getText();
    29.     logic.apply(txt)
    30.   }  
    31. }

    Der Controller und die Logik haben sogut wie nichts miteinander zu tun. Zwei verschiedene Komponenten, von denen der Controller an die Logik weiterleitet.

  6. #6
    User Halbes Megabyte Themenstarter
    Avatar von Crian
    Registriert seit
    02.08.2013
    Fachbeiträge
    552
    Genannt
    32 Post(s)
    Klingt gut. Ich habe Swing halt "im Blut", aber ich hatte auch schon angedacht, ein Testprojekt mit Java-FX zu erstellen. Diese unterstützte Trennung ist nochmal ein Argument mehr.

    Da werde ich hier im Forum aber auch nochmal einen Thread eröffnen, damit ich es dann auch gleich richtig mache und nicht vielleicht mit einer schlechten Anleitung beginne.

  7. #7
    Two Of Three Megabyte Avatar von L-ectron-X
    Registriert seit
    16.07.2006
    Ort
    Drebkau
    Fachbeiträge
    2.277
    Genannt
    103 Post(s)
    Schreibe deinen Beitrag besser im Byte-Welt-Wiki, hier im Forum geht er irgendwann unter. Im Wiki ist eindeutig der bessere Ort.
    Dort können mehrere Leute gemeinsam an einem Beitrag arbeiten.
    Die Zugangsdaten sind die Gleichen, wie für das Forum.
    Schöne Grüße
    L-ectron-X

    Byte-Welt - Wir sind die Community, in der die Benutzer sagen, wohin wir uns entwickeln.
    Programmieren lernt man nur durch Programmieren.

    "Wenn man die Buchstaben von Bundeskanzlerin umstellt, kommt Bankzinsenluder raus..."

+ Antworten Thema als "gelöst" markieren

Direkt antworten Direkt antworten

Schreibe folgendes Wort rückwärts: Dokumentation

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)

Ähnliche Themen

  1. (RMI) RMI - Client von Server komplett trennen?
    Von ZickZack im Forum Netzwerkprogrammierung
    Antworten: 6
    Letzter Beitrag: 30.04.2015, 14:19
  2. Akzeptanztest für komplexe Logik
    Von Fastjack im Forum Allgemeine Themen
    Antworten: 8
    Letzter Beitrag: 06.11.2014, 20:55
  3. Thread-Kommunikation Logik + Renderer
    Von Oneric im Forum Spiele- und Multimedia-Programmierung
    Antworten: 3
    Letzter Beitrag: 19.06.2014, 17:48
  4. Klassen von Daten gruppieren oder trennen?
    Von MOEP_BIBER im Forum Java Enterprise Edition (Java EE)
    Antworten: 7
    Letzter Beitrag: 02.08.2013, 16:26
  5. Verzweiflung bei der Logik
    Von savagedog im Forum Java-Grundlagen
    Antworten: 6
    Letzter Beitrag: 28.07.2011, 03:48

Berechtigungen

  • Neue Themen erstellen: Ja
  • Themen beantworten: Ja
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •