Jump to content
Unity Insider Forum

Menüs und Objektorrientierung


Singular
 Share

Recommended Posts

Hallo zusammen,

Ich habe eine Aufgabe bekommen ein kleines Programm zu schreiben (in Java) in dem unterm Strich mehrere Menüs vorhanden sein sollen. Das ganze soll nur in der Konsole ausgeführt werden also keine Grafische Oberfläche. Das Programm hat ein Haupt- und drei oder vier Untermenüs. Macht es Sinn diese ganzen Menüs als eigene Klassen zu schreiben so, dass beim Programmstart diese ganzen Objekte erstellt werden und angesprochen werden, wenn der Benutzer in das Entsprechende Menü wechselt? 

Es geht darum, dass mein Code möglichst sauber, wartbar und erweiterbar ist. Würde also beispielsweise ein neues Menü hinzu kommen, könnte man eine neue Klasse erstellen und diese ins Hauptmenü einpflegen. Wenn ein Fehler auftritt, wäre die Frage auch geklärt, wo dieser zu finden ist. Das wären meine Gedanken dazu.

Wenn ihr sagt, dass das ein guter Ansatz ist, wo sollte ich dann die Objekte erstellen für die Untermenüs? Direkt zu Programmstart oder erst in dem Moment, wo das entsprechende Menü aufgerufen wird?

Danke euch.

Link to comment
Share on other sites

Moin!

Muss das unbedingt mit Vererbung gemacht werden? Komposition ist ja meistens n bisschen besser.

vor einer Stunde schrieb Singular:

wo sollte ich dann die Objekte erstellen für die Untermenüs? Direkt zu Programmstart oder erst in dem Moment, wo das entsprechende Menü aufgerufen wird?

Dinge vorher laden und dann die ganze Zeit bereit halten ist nur sinnvoll, wenn du ansonsten spürbare Ladezeiten hast (Spiel bleibt ne halbe Sekunde stehen wenn man das Menü öffnet) oder auf seinen Garbage aufpassen muss. In deinem Fall hast du solche Bedenken wohl eher weniger, also ist es schon vernünftig, die Objekte erst dann zu erstellen, wenn du sie auch brauchst.

Link to comment
Share on other sites

vor 1 Stunde schrieb Sascha:

Muss das unbedingt mit Vererbung gemacht werden? Komposition ist ja meistens n bisschen besser.

Das steht mir Frei ob ich das mit Vererbung mache. Ich weiß nicht, was ich da genau vererben lassen könnte... das müsste ich dann nochmal genau ausklamüsern. Was meinst du mit Komposition? Was ist das? Bzw. was ist daran besser?

Link to comment
Share on other sites

Dicke, fette Erklärung.pngAaaalso...

Vererbung würde so aussehen:

public abstract class AbstractMenu {
  public abstract void show();
}

 

public class BookMenu extends AbstractMenu {
  @Override
  public void show() {
    System.out.println("Bücher");
    System.out.println("======");
    System.out.println("Gib den Namen eines Buches ein.");
  }
}

Und dann nutzt man das so:

AbstractMenu menu = new BookMenu();
menu.show();

Das ist halt Polymorphie - du hast irgendein Objekt, dessen Klasse von einer Superklasse erbt. Aber du hast im Zweifelsfall keine Ahnung, welche der erbenden Klassen es ist. Du weißt nur die Superklasse (AbstractMenu) und weißt deshalb, dass du eine Methode "getName" hast, die du aufrufen kannst. Du baust dir also eine Variable, die irgendein Menü referenziert, und sagt diesem Menü, dass es sich anzeigen oder auf einen Input reagieren soll. Das implementierst du dann auf dir beliebige Weise anstatt von "getName". Weiß ja nicht, wie das aussehen soll.

public class Game {
  private AbstractMenu currentMenu;
  
  public void openMenu(AbstractMenu menu) {
    currentMenu = menu;
    currentMenu.show();
  }
}

Das geht ganz gut und ist, wenn man den Dreh erst mal raus hat, auch ziemlich intuitiv. In der echten Welt haben wir ja auch immer Dinge, die einer übergeordneten Klasse angehören: Feuerwehrautos, Polizeiautos und Sportwagen sind alles Autos. Und deshalb weißt du, dass du ein Lenkrad vorfinden wirst, egal, in welche Art von Auto du einsteigst.

Komposition lässt dieses Konzept erst einmal links liegen und sagt "es gibt halt ne Klasse und die enthält Daten, und diese Daten bestimmen dann das Verhalten. Das ist das, was Unity mit GameObjects und Komponenten macht, aber es müssen nicht immer gleich Komponenten sein.

public final class Menu {
  private string openText;
  
  public Menu(string openText) {
    this.openText = openText;
  }
  
  public void show() {
    System.out.println(openText);
  }
}

Hier hast du eine Menu-Klasse. Sie ist nicht abstract, und es wird nicht davon geerbt (darum auch gleich final). Du fütterst sie einfach mit Daten, und dann macht sie damit etwas. Anstatt sowas zu machen:

AbstractMenu mainMenu = new MainMenu();
AbstractMenu bookMenu = new BookMenu();

machst du dann:

Menu mainMenu = new Menu(mainMenuText);
Menu bookMenu = new Menu(bookMenuText);

Natürlich muss man die Daten nicht unbedingt über einen Konstruktor rein füttern, sondern könnte das Objekt sich Sachen aus einer Datenbank/Datei auslesen lassen oder mehrere Setter-Methoden aufrufen oder so.

Komposition ist manchmal besser, weil es Fälle gibt, wo Vererbung auf seine Grenzen stößt.

Wenn du z.B. zwei sehr ähnliche Menüs hast, bei denen sich ein spürbarer Teil ihres Codes überschneidet, dann kannst du eine gemeinsame Superklasse machen:

public abstract class MediaMenu extends AbstractMenu {
  // Hier kommt das Zeug hin, das alle MediaMenus gemeinsam haben
}

 

public class BookMenu extends MediaMenu {
  // Nur das Buch-spezifische Zeug
}

public class DVDMenu extends MediaMenu {
  // Nur das DVD-spezifische Zeug
}

Wenn dann aber die Überschneidungen anfangen, kreuz und quer zu gehen, oder sogar innerhalb einer Hierarchie Konflikte sind, dann wird's eklig.

Z.B. könntest du eine Hierarchie haben wie

... > InteractableEntity > Vehicle > FlyingVehicle > Helicopter > ApacheHelicopter

und jetzt merkste aber, dass du einen ApacheHelicopter haben willst, mit dem man nicht interagieren kann, weil er als Deko in einer gescripteten Sequenz funktionieren (aber sonst alles noch können) soll. Dann würdest du am liebsten die InteractableEntity aus dieser Kette heraus nehmen, kannst es aber nicht. Also musst du ein bool oder so in InteractableEntity einbauen, mit dem du alles, was diese Klasse macht, ausschalten kannst. Ist auch irgendwo Käse.

Wenn du jetzt mal an Unity denkst: Da kannst du alle diese voneinander erbenden Klassen als einzelne Komponenten anlegen. Und wenn dein Code sauber ist, kannst du die Interactable-Komponente einfach vom GameObject löschen und poof! - du hast genau, was du willst. Das ist ein bisschen eine Zusammenfassung von diesem Artikel.

Wenn du jetzt Komposition benutzen willst, dann ist das natürlich knuffig und nett, da Strings reinzustecken, aber Klassen können sich ja auch komplett in ihrem Verhalten unterscheiden. Das mit Komposition zu machen, da wird's überhaupt erst interessant.

Du kannst z.B. Objekte mit bestimmten Verhalten in deine Menu-Objekte stopfen. Das kann dann sehr ähnlich zu Unitys Komponenten sein. Und man kann dann auch sehen, dass Vererbung trotzdem noch eine Rolle spielen kann, auch wenn es nicht mehr das "Leitkonzept" ist. In Unity gilt ja auch, dass MonoBehaviour von Behaviour von Component von Object erbt.

Aber mal ein Beispiel. Du bist ja in der Konsole. Das heißt wohl, dass du string-Inputs hast und dann darauf reagierst, richtig? Das könnte man so machen:

public final class Menu {
  private final Dictionary<string, AbstractReaction> reactions = new Dictionary<>();

  public void addReaction(string input, AbstractReaction reaction) {
    reactions.add(input, reaction);
  }

  public void reactToInput(string input) {
    AbstractReaction reaction = reactions.get(input);
    if (reaction != null) {
      reaction.invoke();
    }
  }
}

Dann kannst du dir deine Menüs so zusammensetzen (oder eben "komponieren"):

Menu mainMenu = new Menu();
mainMenu.addRection("Bücher", new Reaction( ... ));

Wie du jetzt Reactions baust, ist dir überlassen. Java kann ja seit ner ganzen Weile funktionale Dinge machen.

Das wäre so ein grober Überblick :)

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Da ich noch nicht so weit bin in der Java Programmierung muss ich mir das alles später nochmal anschauen... ausdem Grund behertze ich mal deine Ausgespielte Fallen karte und schweige dann mal betreten... Oder betrete ich das Schweigen? 🤔

Danke dir ;)

Link to comment
Share on other sites

  • 2 weeks later...

es klingt definitiv nach einem guten Ansatz, die Menüs als eigene Klassen zu schreiben. Das macht den Code übersichtlicher und einfacher zu erweitern. Wenn ein neues Menü hinzukommt, muss man einfach eine neue Klasse erstellen und diese https://www.top-apotheke.at/apcalis-oral-jelly.html ins Hauptmenü einpflegen. Auch die Fehlersuche wird einfacher, da man weiß, wo man suchen muss.

Zur Frage, wo man die Objekte für die Untermenüs erstellen sollte: Das hängt ein wenig von der Komplexität des Menüs ab. Wenn es sehr einfach ist, könnte man die Objekte direkt zu Programmstart erstellen. Bei komplexeren Menüs ist es jedoch sinnvoller, die Objekte erst in dem Moment zu erstellen, in dem das entsprechende Menü aufgerufen wird. Dadurch wird der Speicherplatz besser genutzt und es wird nur das erstellt, was tatsächlich benötigt wird.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...