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

buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

11

12.10.2011, 13:59

Die draw Methode gehört in keine Klasse. Das hatte ich wohl etwas unglücklich geschrieben. Man kann diese Methode außerhalb definieren. Damit man erkennt, in welchen
"Bereich" diese Methode gehört, kann man einen Namespace verwenden. Oder man definiert einen etwas ausdrucksstärkeren Namen.
Die getter Methode müssen natürlich in die Klasse. Ich betrachte das mal nicht als ironische Frage.
Eine Klasse ist eine Sammlung an Daten und beinhaltet Methoden, die mit diesen Daten arbeiten. Dazu gehört natürlich auch eine getter Methode.
Nehmen wir mal ein anderes Beispiel.
Eine Klasse Vec2:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
class Vec2 {

public:
 Vec2() : m_X(0) , m_Y(0) {}
 Vec2(float x,float y) : m_X(x) , m_Y(y) {}
 float getX() const {
   return m_X;
 }
 usw. usw. 
private:
  float m_X;
  float m_Y;
}


Jetzt möchte man den operator "+" überladen. Also quasi:

C-/C++-Quelltext

1
2
3
Vec2 v(100.0f,100.0f);
Vec2 u(200.0f,200.0f);
Vec2 w = u + v;

Viele würde doch das in die Klasse Vec2 einbauen als Methode. Aber diese Methode ändert weder die Daten in v noch in u. Also gehört sie außerhalb aller Klassen als
eigenständige Methode:

C-/C++-Quelltext

1
2
3
4
namespace math {

  Vec2 operator + (const Vec2& v,const Vec2& u);
}

Der Namespace ist optional hier.
Das meine ich damit.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

12

12.10.2011, 14:07

Naja, da ich etwas Zeit habe, fangen wir doch mal eine OOP Diskussion an.
Also: Warum ist in der Paddle Klasse eine draw Methode? Sie ändert ja keine Daten in der Instanz, also warum hast Du sie in der Klasse?
[...]
Streng nach OOP Regeln sollte man diese Methode eher auslagern:

Würd ich nicht unbedingt sagen, hängt imo stark davon ab. Nach der Logik müsstest du auch deine Getter auslagern, weil die ja auch keine Daten der Instanz ändern.
Wenn wir schon über OOP diskutieren wollen, dann würd ich fragen, was die ganzen Getter da eigentlich sollen... ;)

Die draw Methode gehört in keine Klasse.

Das heißt dann also, deine draw Funktion arbeitet auf globalen Daten!?

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »dot« (12.10.2011, 14:17)


buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

13

12.10.2011, 14:23

Warum mit globalen Daten?
Die draw Methode wäre:

C-/C++-Quelltext

1
2
3
4
void drawPaddle(ALLEGRO_BITMAP* image) {
    al_set_target_bitmap(image);
    al_clear_to_color(al_map_rgb_f(200, 0, 200));
}

oder anders:

C-/C++-Quelltext

1
2
3
4
void drawPaddle(const Paddle& paddle) {
    al_set_target_bitmap(paddle.getImage());
    al_clear_to_color(al_map_rgb_f(200, 0, 200));
}

Also sähe sein Code dann so aus:

C-/C++-Quelltext

1
2
Paddle p(10,10,20,20);
drawPaddle(p);


Ich habe da noch einen Link zu einem interessanten Artikel gefunden: How Non-Member Functions Improve Encapsulation

Aber ich meine das Ganze nicht böse. Ich dachte nur, wir diskutieren mal ein bisschen OOP. Im Büro ist heute nix los und darum habe ich mal ein bisschen Zeit.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

14

12.10.2011, 15:01

Warum mit globalen Daten?

Nunja, deine draw Funktion wird irgendwoher wissen müssen, wohin sie eigentlich malen soll. Nachdem diese Informationen nirgendwo in der Schnittstelle auftauchen, kann es sich nur um globale Daten handeln, in dem Fall stecken diese Daten vermutlich in Allegro.

Ich habe da noch einen Link zu einem interessanten Artikel gefunden: How Non-Member Functions Improve Encapsulation

Ja, in der Tat ein interessanter und sehr empfehlenswerter Artikel. Der Inhalt ist mir persönlich allerdings nicht neu, sondern Teil meiner alltäglichen Praxis ;)
Warum Getter und Setter keine so tolle Idee sind, wird ja in dem Artikel auch schon angerissen. Und genau da seh ich eben ein großes Problem mit der draw Funktion. Damit die freie Funktion dein Paddle zeichnen kann, benötigt sie den getImage() Getter. Damit wird nicht nur die Tatsache, dass das Paddle intern ein einzelnes ALLEGRO_BITMAP hält nach außen propagiert, obwohl es eigentlich ein Implementierungsdetail ist, sondern auch sämtlicher Zeichencode von dieser Tatsache abhängig (und wer weiß was noch alles, immerhin gibt es ja diesen bequemen Getter und ich will ja doch nur schnell mal ...). Wenn du nun plötzlich gerne zwei ALLEGRO_BITMAPs hättest, z.B. weil der Paddle eine magnetische Aura bekommen soll, wirds haarig. Mit den anderen Gettern, die die Position liefern, verhält sich das nicht anders. Getter und Setter sollte man imo so gut es geht vermeiden. Methoden sollten dazu dienen, mit den Daten der Klasse zu arbeiten und nicht dazu, die Daten an dritte weiterzureichen. Ich seh jedenfalls nicht, wo genau die Vorteile der freien draw Funktion liegen. Im Gegenteil, anstatt die Kapselung zu erhöhen, musstest du, um draw() als freie Funktion implementieren zu können, das Interface der Klasse um Getter erweitern, durch die nun jedermann Zugriff auf Teile des internen State des Objektes hat. Wenn du dir das Beispiel mit dem Wombat im von dir verlinkten Artikel genau anschaust, wird dir auffallen, dass dort keine Getter zum Einsatz kommen. Das ist kein Zufall ;)

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


Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

15

12.10.2011, 15:08

Wenn wir schon über OOP diskutieren wollen, dann würd ich fragen, was die ganzen Getter da eigentlich sollen... ;)

da muss ich an hq9++ denken, welches die Beste Umsetzung einer Datenkapselung hat ;D

ein paar Gegenbeispiele:
man denke sich eine Klasse, die Informationen für eine Netzwerkverbindung (u.a. die IP-Adresse)
nun hat diese Klasse 2 Getter
einmal einen, der die IP-Adresse als eine 4 Elemente große Liste ausgibt (der Datentyp ist für das Beispiel erstmal egal)
ein einmal einen, der die IP-Adresse in eine Textuelle Form umandelt ("x.x.x.x")

demnach könnte eine der beiden Methoden ausgelagert werden, da keine von beiden Daten verändert und min. 1 von beiden notwendig ist, um auf diesen Werte/diese Werte zuzugreifen
aber welche sollte denn ausgelagert werden?
ich denke die, die die IP-Adresse in der Form ausgibt, in der sie nicht direkt gespeichert wird
aber was, wenn die IP-Adresse intern als 32 Bit Ganzzahl (vorzeichenlos) gespeichert wird?
(vermutlich werdet ihr das Array präferieren, da ein geringerer Rechenaufwand zur Ermittlung notwendig ist)
aber mal angenommen, man erstellt auch noch eine Getter Methode, die die Zahl in dieser Variante liefert (als Integer), dann müssten doch die anderen beiden Methoden ausgelagert werden (selbst wenn diese neue Methode nur von den anderen beiden verwendet wird)
(das Beispiel ist nicht unbedingt das beste, vielleicht fällt mir noch was besseres ein...)


nehmen wir eine Klasse, die eine Information speichert, die von außen nicht zugänglich sein darf (auch nicht schreibgeschützt)
allerdings sollen dennoch anhand dieser Werte ermittelt werden
wäre das ein schlechtes Design?


wie würde man das in Programmiersprachen handhaben, in denen man keine Funktionen definieren kann? (sprich: unterhalb der Namensräume/Pakete können sich nur Klassen befinden)
was ist, wenn der Autor des Themas feststellt, dass er das Bild nur zum Zeichnen benötigt und deswegen die getImage() Methode entfernt (was zur Folge hätte, dass die draw() Methode in die Klasse aufgenommen werden muss)
wäre das dann ein Verstoß gegen die objektorientierte Programmierung/eine schlechte objektorientierte Programmierung?


(ja, gut, die Frage, ob die Getter ausgelagert werden müssten, war ein wenig dumm, da ansonsten gar kein Zugriff von außen auf die Werte besteht, wodurch keine der Funktionen funktionieren würde...)


Edit: und wieder einmal habe ich lange zum Schreiben gebraucht...
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Sacaldur« (12.10.2011, 15:16)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

16

12.10.2011, 15:16

Ich würde zuallererst einmal die Frage stellen, warum jemand die IP-Adresse von meiner Netzwerkverbindung bekommen muss. Irgendwer muss das Objekt erzeugt haben, d.h. diese Information ist wo anders bereits vorhanden. Will ich wirklich, dass sie durch dieses Objekt nun in alle Welt hinausgetragen wird?

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

17

12.10.2011, 15:27

Ich würde zuallererst einmal die Frage stellen, warum jemand die IP-Adresse von meiner Netzwerkverbindung bekommen muss.

warum "jemand"?
stell dir mal einen Server vor (meinetwegen von einem Spiel)
irgendwann verstößt einer der Clients gegen die Regeln und soll gebannt werden (durch eintragen der IP-Adresse auf eine Blacklist)
gut, das kann man immernoch lösen, ohne dass die IP-Adresse von Interesse ist
was ist aber, wenn man sich Informationen zu dem Client ansehen möchte, wo die IP-Adresse dazu gehören würde? (datenschutzrechtliche Bedenken mal außen vor)
oder vlt. will der Client Informationen über den Server erfahren

[...] diese Information ist wo anders bereits vorhanden.

es ist durchaus sinnvoll, Daten einmal zu verwalten und sich keine Redundanzen anzuschaffen
allerdings kann es sich bei dem Objekt mit der IP-Adresse um das eine Objekt handeln, welches diese IP-Adresse speichert - dann wäre sie eben nicht an anderer Stelle vorhanden
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

18

12.10.2011, 15:46

Nun gut, das ist also ein Beispiel für einen Fall, wo ein Getter unter Umständen sinnvoll sein wird. Man beachte allerdings, dass die IP-Adresse normalerweise kein Implementierungsdetail bzw. interner Zustand des Objektes ist, zumindest in dem Sinn, dass ihr Wert die Operation des Objektes in irgendeiner Form beeinflusst. Der Sockethandle über den die Verbindung kommuniziert dagegen schon, der sollte auf keinen Fall öffentlich zugänglich sein. Wenn man dann einen Getter macht, sollte die IP-Adresse in einer nativen Form oder in Form eines entsprechenden Objektes zurückgegeben werden. Die verschiedenen Arten wie eine IP-Adresse formatiert werden kann, hat weder mit der Adresse an sich, noch der Netzwerkverbindung irgendwas am Hut. Dafür würd ich evtl. freie Funktionen verwenden.

[...] diese Information ist wo anders bereits vorhanden.

es ist durchaus sinnvoll, Daten einmal zu verwalten und sich keine Redundanzen anzuschaffen
allerdings kann es sich bei dem Objekt mit der IP-Adresse um das eine Objekt handeln, welches diese IP-Adresse speichert - dann wäre sie eben nicht an anderer Stelle vorhanden

Ich wollte damit eigentlich nicht auf das Minimieren von Redundanzen hinaus und mir ist klar, dass Information irgendwo gespeichert sein muss. Worauf ich hinauswollte ist: Das Objekt muss diese Information von irgendwoher bekommen. Wenn ich diese Information benötige, könnte ich sie mir nicht an der Quelle beschaffen? Wenn ich die Quelle nicht kenne, warum kenne ich sie nicht, versuch ich nicht vielleicht gerade etwas zu tun, was der Natur meines Designs widerspricht? Brauch ich diese Information wirklich für das, was ich tun will, oder könnte ich nicht einfach Methoden von Objekten benutzen, die ich kenne, um mein Ziel zu erreichen? Ist es wirklich sinnvoll und notwendig, den Code hier vom konkreten Konzept einer IP-Adresse abhängig zu machen? Man sollte eben einfach erstmal innehalten und drüber nachdenken, was man eigentlich gerade zu tun gedenkt und ob das so wirklich eine gute Lösung ist. Dass die Antwort immer noch "Ja" sein kann, schließ ich ja nicht aus.
Ich würde die IP-Adresse jedenfalls lieber bei dem "Client" Objekt abfragen, das die Netzwerkverbindung zu dieser Adresse erzeugt hat und intern verwendet, als bei der Verbindung direkt. Denn die Tatsache dass ich dort, wo ich die IP-Adresse eines Client ausgeben will, Zugriff auf dessen interne Netzwerkverbindung hab, würde mir den Schlaf rauben ;)

Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von »dot« (12.10.2011, 16:00)


Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

19

12.10.2011, 16:08

die Quelle könnte eine Benutzereingabe, eine Liste mit vorher vom Benutzer gespeicherten Adressen oder eine eingehende Verbindung beim Server

ich habe doch nie geschrieben, dass die IP-Adresse von der Verbindung kommen soll 8| (ich hatte von einer Klasse geschrieben, welches Verbindungsinformationen ("Informationen für eine Netzwerkverbindung") enthält)
außerdem habe ich nicht geschrieben, dass es sich bei der gedachten Klasse nicht um die Clientklasse handeln kann (ich habe nur geschrieben, dass diese die IP-Adresse enthält und dass es für die IP-Adresse Getter gibt)

(beim Schreiben hatte ich ein wenig etwas im Kopf, wie die Klasse "InetAdress" unter Java - in dem von mir genannten Beispiel würde die Klasse ungefähr die gleiche Information haben, wie InetAdress)
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

20

12.10.2011, 16:21

Ok sry, dann hab ich das etwas fehlinterpretiert. Dann sind wir uns also einige was die IP-Adressen Geschichte angeht. Aber nur weil Getter eben vereinzelt evtl. doch sinnvoll sein können, heißt das aber noch lange nicht, dass das immer so ist ;)

Werbeanzeige