Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

51

25.07.2012, 19:53

Getter braucht man dann imo aber schon wieder nicht. Mein D3D GUI System beispielsweise, speichert überhaupt nur direkt das Layout der Glyphen in den UI Objekten und überhaupt keine semantische Information über den Text. Denn der Text muss ja von irgendwo herkommen, die semantische Information steckt also schon dort und gehört auf keinen Fall in die UI Objekte...
Ohne Getter kannst Du aber auch die Elemente nicht in einem Editor zusammenstellen, denn dieser könnte die Werte ja nie wieder auslesen.

Möglicherweise, möglicherweise auch nicht. Wie gesagt, lässt sich das eigentlich immer nur für die konkrete Anwendung beantworten. In meinem UI sind das logische und das graphische Modell getrennt, das Ganze ist strukturell ein klein bisschen von WPF inspiriert. Das logische Modell arbeitet mit dem graphischen Modell, letzteres enthält keinerlei semantische Information. Irgendwer in der logischen Schicht muss den Text aber setzen und ihn daher natürlich kennen. Es gibt absolut keinen Grund, den Text in den Visuals zu halten; man könnte sogar argumentieren, dass dadurch das Single Responsibility Prinzip verletzt würde...

Maximale Lebenspunkte und Haarfarbe würde ich jetzt mal eher als Kandidaten für unveränderliche Attribute sehen.
Unveränderlich nur bedingt, denn man muss dieses Maximum ja von Außen festlegen können, sonst kannst du nirgends verschiedene Gegner entwerfen.

Wieso? Man kann diese Werte über den Konstruktor angeben oder sonstwas. Es gibt auch für dieses Beispiel wieder keine allgemeine Antwort.

Zitat von »BlueCobold«

[...] die Position eines Objekts in der Welt, etc pp?
Ja, da braucht man möglicherweise einen Setter, aber vermutlich keinen Getter. Oder umgekehrt.
Wenn das Modell sich selbst rendern kann, dann braucht es keinen Getter. Aber dann ist es automatisch ein ModelView, was auch nicht immer sonderlich cool ist. Wahlweise hat man dann eventuell ein Problem, dass Projektile oder andere Spieler/NPCs sich nie auf dieses Objekt hin bewegen könnten, weil sie die Position ja nicht abrufen können.

Auch hier wieder: Man kann und sollte Graphik von Logik trennen, ich hab niemals gesagt, dass es ein und das selbe Objekt sein sollte oder gar muss.

Hängt davon ab wie das Objekt gerendert wird. Aber in der Regel hast du Objekte, die sich selbst rendern, daher brauchst du auch hier wieder entweder nur einen Getter oder nur einen Setter, auf keinen Fall aber beide.
Wenn Du das hast, sprich einen ModelView, dann heißt das aber auch, dass Du das Modell nicht verändern kannst, während es sich rendert. Parallelität ausgeschlossen, weil Seiteneffekte es unmöglich machen würden.

Seiteneffekte sind in der Regel genau das, was Parallelität erst schwierig macht. Ein weiterer Grund aus dem man Getter und Setter vermeiden sollte, den ich vorhin für einen Moment sogar auch schon anführen wollte. Abgesehen davon, sprach ich nicht von einem ModelView. Wer sagt, dass die logische und graphische Repräsentation ein und das selbe Objekt sein müssen!? Das würde ich eigentlich eher vermeiden wollen...

Nehmen wir dazu als Beispiel die Sache mit den Positionen. Wenn ich die Position im graphischen Modell halte und das logische Modell auf diese Information zugreift (oder umgekehrt), dann hab ich die potentiell sehr hohe Nebenläufigkeit dieser beiden eigentlich völlig unabhängigen Systeme evtl. mit einem Schlag drastisch reduziert. Dabei steckt hinter einer "Position" in beiden Schichten möglicherweise sogar ein völlig anderes Konzept. Im Renderer vielleicht direkt eine Matrix, in der Logik irgendeine andere Koordinatenrepräsentation. Informationsfluss in beide Richtungen sollte imo jedenfalls äußerst selten tatsächlich nötig sein...

Generell stimme ich Dir schon zu, dot, aber wenn man anfängt die wildesten Spagate zu machen, weil man Setter und Getter umgehen will, dann wird das Ergebnis noch deutlich hässlicher, als wenn man sie einfach verwendet hätte.

Nun, meine Erfahrung ist, dass es eigentlich nie "wilde Spagate" braucht. Es braucht nur ein fundamental anderes Design, das am Ende aber meist sehr viel flexibler und eleganter ist. Auch sag ich ja nicht, dass man absolut nie und nimmer Getter oder Setter verwenden darf. Man sollte aber auf jeden Fall versuchen, Getter und Setter zu vermeiden und spätestens ein Objekt, das Getter und Setter, also eine Property, die gelesen und geschrieben werden kann, hat, ist meiner Erfahrung nach praktisch immer als Code Smell zu werten...

Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von »dot« (25.07.2012, 20:20)


BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

52

25.07.2012, 22:27

Möglicherweise, möglicherweise auch nicht. Wie gesagt, lässt sich das eigentlich immer nur für die konkrete Anwendung beantworten. In meinem UI sind das logische und das graphische Modell getrennt, das Ganze ist strukturell ein klein bisschen von WPF inspiriert. Das logische Modell arbeitet mit dem graphischen Modell, letzteres enthält keinerlei semantische Information. Irgendwer in der logischen Schicht muss den Text aber setzen und ihn daher natürlich kennen. Es gibt absolut keinen Grund, den Text in den Visuals zu halten; man könnte sogar argumentieren, dass dadurch das Single Responsibility Prinzip verletzt würde...
Ich sagte nicht, dass Visual und Logik vermanscht bei mir sind. Aber das logische Konstrukt muss den Text halten, daraus Grafik generieren und den Text auch nach außen wieder auslesbar anbieten. Ich sehe nicht, wie man das verhindern will. Auch in Deinem Beispiel bleibt mir unklar, wie die logische Schicht das bei dir anders machen will.

Wieso? Man kann diese Werte über den Konstruktor angeben oder sonstwas. Es gibt auch für dieses Beispiel wieder keine allgemeine Antwort.
Genau. Und statt nur maximalen Hitpoints im Konstruktor kommt dann noch die Haarfarbe, die Hose, die Jacke, die Schuhe, die Waffe, die Hautfarbe, Gesichtstyp und noch ca. zwei Dutzend andere Charakter-Eigenschaften dazu. Hübscher Konstruktor... Und wenn Du jetzt dem Player eine andere Jacke verpassen willst, musst Du den alten vernichten und einen neuen erzeugen? Vielleicht verstehe ich Dich auch einfach nur falsch, aber wie willst du den Usecase: "Als Spieler möchte ich eine Spielfigur steuern können, welche komplett customized werden kann." technisch gestalten. Wie würdest Du das lösen ohne Setter und Getter? Und wie willst Du das Teil dann rendern ohne dass das Modell die graphischen Repräsentations-Objekte erzeugt?

Auch hier wieder: Man kann und sollte Graphik von Logik trennen, ich hab niemals gesagt, dass es ein und das selbe Objekt sein sollte oder gar muss.
Dann nenn mir doch mal konkret wie Du das kapseln würdest, damit Du keine Setter oder Getter benötigen würdest. Und bitte nicht wieder mit "Im Konstruktor". So viele Parameter hat kein vernünftiger Konstruktor.

Nun, meine Erfahrung ist, dass es eigentlich nie "wilde Spagate" braucht. Es braucht nur ein fundamental anderes Design, das am Ende aber meist sehr viel flexibler und eleganter ist. Auch sag ich ja nicht, dass man absolut nie und nimmer Getter oder Setter verwenden darf. Man sollte aber auf jeden Fall versuchen, Getter und Setter zu vermeiden und spätestens ein Objekt, das Getter und Setter, also eine Property, die gelesen und geschrieben werden kann, hat, ist meiner Erfahrung nach praktisch immer als Code Smell zu werten...
Dann sehe ich nicht, wie man jemals einen Editor für Spiele bauen können will ohne Code-Smell. Irgendwelche Objekte müssen nun mal die Daten halten, die müssen rein und die müssen wieder raus. Da nur Container zu machen und dann Konstruktoren mit den Containern zu invoken klingt für mich nicht nach einem vernünftigen Design, auch wenn Du so ein Design gar nicht vorgeschlagen hast. Etwas anderes fällt mir da aber beim besten Willen nicht ein. Wollte man Objekte nicht konfigurieren können, dann bräuchte man vermutlich wirklich keine Getter oder Setter, das klingt für mich aber nach Hardcoding von Werten oder manuellem Hex-/XML-en von Config-Files. Sehr unbequem und WYSIWYG-unfreundlich.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

53

26.07.2012, 00:11

Ich sagte nicht, dass Visual und Logik vermanscht bei mir sind. Aber das logische Konstrukt muss den Text halten, daraus Grafik generieren und den Text auch nach außen wieder auslesbar anbieten. Ich sehe nicht, wie man das verhindern will. Auch in Deinem Beispiel bleibt mir unklar, wie die logische Schicht das bei dir anders machen will.

Bei einem Label muss ich den Text nur setzen, nicht auslesen. Bei einem Eingabefeld muss ich mir natürlich in der Tat den Text merken, brauch aber keinen Getter, da ich den Text einfach dem Callback, das aufgerufen wird, wenn der Text sich ändert, übergeben kann, welches wiederum im Konstruktor übergeben wird. Woher die Logik den Text nimmt, den sie in das Label packt oder was sie mit dem Text tut, der aus dem Eingabefeld kommt, ist Sache des Users der UI Bibliothek und nicht der Bibliothek selbst. Und damit haben wir wieder Datenfluss nur in eine Richtung. Unter Logik versteh ich den Code, der die UI Bibliothek benutzt.

Wieso? Man kann diese Werte über den Konstruktor angeben oder sonstwas. Es gibt auch für dieses Beispiel wieder keine allgemeine Antwort.
Genau. Und statt nur maximalen Hitpoints im Konstruktor kommt dann noch die Haarfarbe, die Hose, die Jacke, die Schuhe, die Waffe, die Hautfarbe, Gesichtstyp und noch ca. zwei Dutzend andere Charakter-Eigenschaften dazu. Hübscher Konstruktor...

Ich denk, du wirfst hier einfach zu viele Konzepte in ein Objekt. Die Haarfarbe ist vermutlich nur ein Attribut der graphischen Repräsentation und für die Spiellogik völlig irrelevant. Was der Character gerade an hat, hat wohl nicht unbedingt was im selben Objekt zu suchen wie z.B. der Name des Characters.

Und wenn Du jetzt dem Player eine andere Jacke verpassen willst, musst Du den alten vernichten und einen neuen erzeugen?

Nein, ich könnte z.B. einfach nur das Objekt, das die Ausrüstung des Spielers hält, neu erzeugen, was aber natürlich möglicherweise nicht wirklich sinnvoll ist. Dann verpass ich ihm einen Setter. Nur weil es einen Setter gibt, brauch ich noch lang keinen Getter...

Und wie willst Du das Teil dann rendern ohne dass das Modell die graphischen Repräsentations-Objekte erzeugt?

Muss ich doch nicht. Das Modell erzeugt eben die graphische Repräsentation!? Wieso das deiner Meinung nach Getter und Setter an allen Ecken und Enden impliziert, kann ich grad nicht so ganz nachvollziehen.

Auch hier wieder: Man kann und sollte Graphik von Logik trennen, ich hab niemals gesagt, dass es ein und das selbe Objekt sein sollte oder gar muss.
Dann nenn mir doch mal konkret wie Du das kapseln würdest, damit Du keine Setter oder Getter benötigen würdest. Und bitte nicht wieder mit "Im Konstruktor". So viele Parameter hat kein vernünftiger Konstruktor.

Ich kann konkrete Antworten nur für konkrete Beispiele geben. Wenn ein Konstruktor viele Parameter hat, dann ist das ein Zeichen, dass das Objekt zuviel tut.

Irgendwelche Objekte müssen nun mal die Daten halten, die müssen rein und die müssen wieder raus.

Sie müssen meistens eben eigentlich nur in eine Richtung und nicht in beide. Wenn ich eine Klasse hab, die meinen Helden mitsamt seiner Ausrüstung repräsentiert, dann kennt die natürlich den Held und die Gegenstände, die er an hat. Es wird sinnvoll sein, die Gegenstände, die er an hat, ändern zu können. Um jetzt den Rüstungswert meines Helden zu bestimmen, könnte ich natürlich lauter Getter anbieten, mir alle Gegenstände holen und den Wert berechnen. Oder ich geb der Klasse, die die Items kennt eine Methode, die genau das macht. Und hab wieder entweder nur Setter oder Getter und nicht beides...

Und nochmal: Ich sag nicht, dass es absolut keine Anwendung für Getter oder Setter gibt. Ich sag aber, dass man sie meiner Erfahrung nach in der Regel nur sehr selten braucht, ganz besonders beide auf einmal. Denn wenn ich ein Objekt hab, das sowohl Getter als auch Setter für ein und die selbe Sache anbietet, hab ich es effektiv mit einem Objekt zu tun, das nichts anderes tut, als Daten für andere Objekte zu halten, was meiner Erfahrung nach eben üblicherweise auf Schwächen im Design hindeutet. Denn solch ein Objekt ist eben oft Symptom dafür, dass irgendwo Abhängigkeiten nicht wirklich durchdacht oder gar völlig außer Kontrolle geraten sind, oder Garant dafür, dass das früher oder später passieren wird. Denn wenn ich ein Objekt hab, das seine Daten offenlegt, dann wird es nicht lange dauern, bis irgendein anderes Objekt was mit diesen Daten anstellen wird. Und ehe man sich's versieht, kommt das nächste Objekt und verwendet die Daten, weil's grad im Moment einfacher als die saubere Lösung war. Und das nächste. Und das nächste. Und ... schon hab einen Filz aus Objekten, die alle irgendwie voneinaner abhängig sind. Ist ja auch mit Singleton und globalen Variablen im Prinzip genau das Gleiche...

Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von »dot« (26.07.2012, 01:07)


BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

54

26.07.2012, 06:33

Du findest also, dass es gutes Design und gute Entkopplung wäre, wenn

A) Ein Modell seine eigene graphische Repräsentation zusammenbastelt und dies nicht komplett einer anderen Schicht überlässt, die sich dann raus sucht, welche Daten sie für relevant für die Darstellung hält und diese dann vom Modell abruft? Finde ich ehrlich gesagt etwas merkwürdig und nicht sonderlich flexibel. Das Model wäre hier übrigens auch ein View, weil es ja die graphischen Elemente selber erzeugt (egal in welcher Schicht die liegen, das Model erzeugt sie).

B) Ein Modell die Business-Logik selber berechnet wie z.B. den angesprochenen Rüstungswert des Helden. Das Modell würde da sämtliche Ausrüstung, Buffs oder weiß der Geier was selbst heran ziehen, um die finalen Werte zu berechnen. Als nächstes kennt das Player-Model also vermutlich auch die Formeln zur Berechnung von Schaden, zur Schadens-Reduktion, zur Bewegungsgeschwindigkeit und so weiter? Es ist also kein reines Model mehr, sondern ebenfalls ein Controller.

Aus (A) und (B) folgt, dass Dein Model immer ein ModelViewController wäre, was nicht sonderlich hilfreich ist, wenn man nach MVC arbeitet. Heißt nicht, dass MVC ein sinnvolles Konzept ist, ich bin ein großer Verfechter von (A) und auch (B) macht in gewissen Auswüchsen Sinn, aber auch nur so weit, wie (B) wirklich etwas mit dem Modell zu tun hat. Schadensberechnung gehört aber sicher nicht dazu. Man könnte für solche Berechnungen natürlich einen entsprechenden Calculator injecten, der die Werte dann als BlackBox aus den übergebenen Eigenschaften berechnet, wirklich entkoppelt wäre das aber auch nicht.

Zu der Sache mit dem Eingabefeld einer UI: Wenn ein Editor den Text eines Elements nicht auslesen kann, sondern nur über das Callback erfährt (Callback ist hier generell erstmal eine sinnvolle Sache), dann muss irgendjemand den aktuellen Text des Felds separat intern halten, damit immer der aktuelle Zustand bekannt ist. Das halte ich für sehr schlechte Redundanz. Man stelle sich dafür vor, ein Spiel zeige ein Menü an mit einem darin enthaltenen Text-Feld. Das Text-Feld hat einen Default-Wert. Dieser wird vom Spieler nicht geändert, sondern er drückt einfach nur auf den "Save-Button". Woher weiß nun das Spiel, welcher Wert sich in diesem Feld befindet, damit es diesen in seine Konfiguration übernehmen kann? Man könnte jetzt argumentieren, dass natürlich der Wert ja vorher schon in der Konfig stehen müsste und da er nicht geändert wurde, auch korrekt sei. Das muss aber nicht so sein. Man stelle sich dazu vor dieser Eintrag in der Konfig sei gelöscht worden, um den initialen wieder herzustellen (durchaus logischer Usecase). Also, woher genau weiß das Game, welcher Wert da drin steht? Oder woher weiß das ein UI-Editor, der nicht in der Lage ist das Element nativ anzuzeigen (bei Editoren ja nicht unbedingt unüblich, auch wenn das für meine nicht zutrifft). Da wurde ein Element so "schön beschissen gebastelt"[Zitat BeatleJuice], dass man an den aktuellen Wert nicht heran kommt und keine andere Chance hat als das Element zu rendern, damit der User den Wert erfährt. Auch das klingt für mich nicht gerade sinnvoll.

Bis zu einem gewissen Punkt stimmen wir beide sicherlich überein, Container-Klassen mit lauter Gettern- und Settern sind ein deutliches Anzeichen für schlechtes Design. Genau so etwas haben wir auf Arbeit, da darf nicht einmal ein Modell ein anderes kennen, wo ich schon die Hände über dem Kopf zusammenschlage und mich frage, wozu man dann noch ein Modell braucht - gar nicht, aber man braucht Daten-Container. Die Logik und Beziehungen zwischen allen wird nur über Business-Logik-Services abgebildet. Gruselig und meiner Meinung nach so schlecht, wie es überhaupt nur möglich war. Die Idee dahinter war die konkreten Implementierungen austauschbar zu machen (OSGi- und Service-Landschaft) und keine Abhängigkeiten zwischen den einzelnen Plugins und Implementierungen aufzubauen, alles modular halten. Total vergeigt... aber ich schweife ab. Wie gesagt gehe ich bei Deinen Argumenten ein Stück weit mit, aber manche Sachen halte ich für zu radikal. Wenn Getter und Setter dazu missbraucht werden die eigentlich zu einem Objekt gehörende Logik extern abzubilden, dann läuft da natürlich grundsätzlich etwas gegen den Gedanken von OOP, Klassen allein und Gruppierung von reinen Eigenschaften in Klassen hinein ist eben kein vernünftiges OOP, sondern da ist etwas gründlich missverstanden worden, da hast Du absolut Recht (auch wenn Du es nicht genau so gesagt hast, aber ich denke, dass Du zustimmen würdest). Deine Ideen finde ich aber doch etwas radikal, muss ich sagen, denn ich denke, dass viele Sachen von außen les- und schreibbar sein müssen, damit andere Komponenten mit den Daten sinnvoll arbeiten können. Man nehme hier wieder das Beispiel der Jacke des Spielers, welche man in einem Editor per ComboBox ändern könnte und wo die aktuell gewählte Jacke in der Combo vorgewählt ist. Ohne Setter kann ich sie nicht ändern. Ohne Getter weiß ich nicht, welche der Spieler an hat. Gerade bei solchen Eigenschaften finde ich es aber wichtig, dass sie änderbar und einsehbar sind. Das heißt nicht, dass die Logik, die später mit dem Spieler arbeitet, diese unbedingt benötigt, da würden die meisten meiner Objekte mit nur einer Set- oder einer Get-Methode für die jeweilige Property auskommen und genau das machen sie auch. Alle Elemente lesen ihre Eigenschaften aus Konfig-Files, auf die Getter und Setter greift keine Stelle des Spiels selbst zu. So ein Zugriff ist auch nicht möglich, weil diese Setter und Getter in der Oberklasse gar nicht bekannt sind. Zum Beispiel gibt es bei mir Animationen - Man kann sie starten (, eine StartPosition festlegen), stoppen, abfragen, ob sie noch laufen, wann sie beendet wurden, welches ihre aktuelle Position ist und sie mit einem Offset rendern. Es gibt aber auch einen Untertyp Billboard-Animation. Diesem kann man Sprites zuweisen, Transparenz-Verläufe, Farb-Verläufe, etc. Die Oberklasse weiß davon aber nichts, muss sie auch nicht und nur mit dieser Oberklasse wird überall (außer im Editor) gearbeitet.
Getter und Setter komplett privat zu machen, sodass man in einem Editor nicht damit arbeiten kann, das wäre für mich allerdings mehr als gruselig, denn ich will schon wissen, welche Textur eine Billboard-Animation verwendet, welche Key-Frames sie besitzt, wie viele Lebenspunkte, Rüstung oder welche Ausrüstung mit welchen Eigenschaften eine Einheit hat - das sehe ich ihr ja schließlich nicht an. Das will ich aber einsehen und editieren können.

Mein Fazit ist daher:
Setter und Getter anbieten ist erstmal nicht unbedingt falsch - kann es für viele Properties sein, für andere wiederum ist es sinnvoll. Intensiver Gebrauch dieser Setter und Getter durch externe Klassen, die mit den Werten dann irgendwas eigenständig anstellen, das aber halte ich durchaus für ein sehr deutliches Anzeichen von schlechtem Design. Ein Editor oder Konfig-Menü wäre danach also eigentlich schon schlechtes Design, aber der Anwendungsfall ist hierbei natürlich auch sehr speziell, denn dabei geht es nicht um Logik, sondern rein um's Manipulieren der Basis-Eigenschaften.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von »BlueCobold« (26.07.2012, 07:17)


Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

55

26.07.2012, 09:15

da ich denke, dass diese Textstellen für die aktuelle Diskussion relevant sind:
Draw thyself
One ramification of full field encapsulation is in user interface (UI) construction. If you can't use accessors, you can't have a UI builder class call a getAttribute() method. Instead, classes have elements like drawYourself(...) methods.
A getIdentity() method can also work, of course, provided it returns an object that implements the Identity interface. This interface must include a drawYourself() (or give-me-a-JComponent-that-represents-your-identity) method. Though getIdentity starts with "get," it's not an accessor because it doesn't just return a field. It returns a complex object that has reasonable behavior. Even when I have an Identity object, I still have no idea how an identity is represented internally.
Of course, a drawYourself() strategy means that I (gasp!) put UI code into the business logic. Consider what happens when the UI's requirements change. Let's say I want to represent the attribute in a completely different way. Today an "identity" is a name; tomorrow it's a name and ID number; the day after that it's a name, ID number, and picture. I limit the scope of these changes to one place in the code. If I have a give-me-a-JComponent-that-represents-your-identity class, then I've isolated the way identities are represented from the rest of the system.
Bear in mind that I haven't actually put any UI code into the business logic. I've written the UI layer in terms of AWT (Abstract Window Toolkit) or Swing, which are both abstraction layers. The actual UI code is in the AWT/Swing implementation. That's the whole point of an abstraction layer—to isolate your business logic from a subsystem's mechanics. I can easily port to another graphical environment without changing the code, so the only problem is a little clutter. You can easily eliminate this clutter by moving all the UI code into an inner class (or by using the Façade design pattern).

When is an accessor okay?
First, as I discussed earlier, it's okay for a method to return an object in terms of an interface that the object implements because that interface isolates you from changes to the implementing class. This sort of method (that returns an interface reference) is not really a "getter" in the sense of a method that just provides access to a field. If you change the provider's internal implementation, you just change the returned object's definition to accommodate the changes. You still protect the external code that uses the object through its interface.
Next, I think of all OO systems as having a procedural boundary layer. The vast majority of OO programs runs on procedural operating systems and talks to procedural databases. The interfaces to these external procedural subsystems are generic by nature. Java Database Connectivity (JDBC) designers don't have a clue about what you'll do with the database, so the class design must be unfocused and highly flexible. Normally, unnecessary flexibility is bad, but in these boundary APIs, the extra flexibility is unavoidable. These boundary-layer classes are loaded with accessor methods simply because the designers have no choice.
In fact, this not-knowing-how-it-will-be-used problem infuses all Java packages. It's difficult to eliminate all the accessors if you can't predict how you will use the class's objects. Given this constraint, Java's designers did a good job hiding as much implementation as they could. This is not to say that the design decisions that went into JDBC and its ilk apply to your code. They don't. We do know how we will use the classes, so you don't have to waste time building unnecessary flexibility.

bezüglich des Renderns eines Objekts:
das Objekt, welches dieses zeichnen muss, muss nicht zwingend ein vollkommen unabhängig davon im Raum stehendes sein
in Java gibt es beispielsweisweise innere Klassen, es sind aber auch innere Interfaces möglich
Klassen, die diese implementieren, können dann auf mehr als nur die öffentlichen Methoden und Eigenschaften zugreifen
ich denke, auch wenn für das Abholen der Informationen dann immernoch Getter verwendet werden, wäre dennoch eine wesentlich besser Datenkapselung gegeben, da die implementierende Klasse des inneren Interfaces als Teil der Klasse (mit innerem Interface) gesehen werden kann und daher Zugriff haben darf
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

56

26.07.2012, 09:47

Innere Klassen sind eine stärkere Verbindung als "Friend Classes" und können nicht einmal ausgetauscht werden, sie sind fest implementiert. Obwohl sie an manchen Stellen sicher sinnvoll sind, weil sie wie Du gesagt hast, Zugriff auf private Teile der darüber liegenden Klasse haben und nach außen völlig transparent als Interface agieren, ist dennoch fraglich, ob sich solche Cross-References und -Zugriffe gut warten lassen. Meiner Erfahrung nach ist das leider nicht der Fall. Hier geht oft auch ein sauberer Weg über einen Konstruktor und Callbacks. Aber wie gesagt, sie haben gewisse Nutzen. Gerade die in Java üblichen Listener und Runnables sind vor allem schnell mal als anonyme Klasse in einen View integriert. Mir fällt da ganz spontan "Display.runAsynch" ein und da wird das ja doch sehr intensiv praktiziert. Alles, was über 20 Zeilen hinaus geht, ist dann aber eventuell nicht mehr so einfach zu durchblicken und sollte eventuell ausgelagert werden und keine heimlichen Zugriffe auf private Member oder Methoden durchführen. Es handelt sich dabei ja nicht mehr um eine Art Embryo der Klasse (winzer innerer Teil separat gekapselt), sondern eher eine ausgewachsene Helper- oder Business-Logik-Klasse mit eigenständigem Lebenszweck.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

57

26.07.2012, 11:54

An sich wollt ihr alle das selbe sagen. Getter/Setter können oft verhindert werden und werden aus Faulheit eingesetzt. Oft geht es aber halt nicht ohne. Dabei habt ihr aber auch recht, dass in den meisten Fällen Get xor Set ausreichend ist. Wenn ich mir den ersten Post hier angucke, dann ging es aber eigentlich um den Unterschied wischen Get/Set und public Members. Und das eine öffentliche Variable in jedem Fall verhindert werden sollte, seht ihr da auch so. Wobei mir hier einige schon sehr weit gehen. Klar kann ich mir für alles und jeden Manager schreiben, die dann intern zusätzliche Daten halten und aus einem Objekt am Ende 3 oder 4 machen. Das kann Code aber auch extrem aufblähen und unübersichtlich machen. Da kommt es halt immer auf den Anwendungsfall an. Das ist meiner Meinung nach eigentlich das wichtigste. Ich hab es oft genug auf der Arbeit erlebt, dass Code umgestellt und angepasst wurde, oder direkt aufwendig geplant wurde, damit es im Sinne von OOP schöner ist. Oft hat aber gerade dies unglaublich viel mehr Aufwand nach sich gezogen und der Nutzen dabei war oft gering bis nicht vorhanden. Man muss halt die Fälle abwägen und sich überlegen wann weniger manchmal vielleicht doch mehr ist. Vor allem als unerfahrener Anfänger kann man sich mit OOP Gehabe schnell selbst überfordern. Da wird noch ein Entwurfsmuster reingeklatsch und noch mehr Abhängigkeiten vernichtet und am Ende ist man selbst total überfordert. Dafür benötigt man nun mal Erfahrung und Know How.
Aber bevor ich weiter abschweife. Wie gesagt eigentlich sind hier so wies für mich aussieht alle der fast gleichen Meinung.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

58

16.01.2014, 11:40

Edit by dot: Abgetrennt von hier: Die Programmiersprache XièXiè


Ich persönlich würde ja von Properties eher Abstand nehmen...

Gibt es eigentlich schon ein Konzept von Klassen oder überhaupt eines Typsystems? Wie sieht es mit Vererbung aus?

Du hast offenbar eingebautes Reference Counting? Wie genau werden zyklische Abhängigkeiten vermieden bzw. behandelt? Gibt es andere Formen von Besitzverhältnissen? Wenn nein würde mich interessieren, wieso du dich gerade für Reference Counting entschieden hast.

Verfolgst du in der Sprache eigentlich irgendeine konkrete Vision bzw. Designphilosohpie? Vermutlich empfielt es sich generell, sich mal bei den verschiedensten anderen Sprachen umzusehen. Wirf z.B. mal einen Blick auf Go, die haben eine sehr interessante Umsetzung von Interfaces...

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »dot« (16.01.2014, 18:56)


TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

59

16.01.2014, 11:46

Ich persönlich würde ja von Properties eher Abstand nehmen...


Du musst sie ja nicht verwenden. Also ist doch wohl auf jeden Fall viel konfortabler als Getter- und Setter zu tippen. Warum sollte man sonst Abstand nehmen?

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

60

16.01.2014, 11:51

Natürlich ist es komfortabler als Getter und Setter zu tippen. Die Frage ist viel eher, wieso genau man das Tippen von Gettern und Settern komfortabel machen sollte. Getter und Setter untergraben eines der Fundamente von OOP, nämlich die Idee der Kapselung. Natürlich ist OOP nicht die Antwort auf alle Fragen; dann stellt sich aber die Frage: haben Properties außerhalb der OOP sinnvolle Anwendungen? Was für Programmierstile möchtest du in deiner Sprache unterstützen!? ;)

Werbeanzeige