?
Hi,
ich weiß, dass dieser Thread nun schon einige Zeit her ist, aber mich interessiert ganz speziell ein bestimmtes Problem:
Ich hab eine best. Klasse, sagen wir "sprite" (wie viele das aus der Spieleprogrammierung kennen). Dieses Dingen hat eine Position in Form eines Vektors (2D oder 3D ist eigtl egal, ich nehmn ma 3D): vector<float> pos; Aufgrund von OOP- und Kapselungsprinzipien kommt es für mich nicht in Frage pos public zu machen, heißt also "private: vector<float> pos;" Jetzt muss der Benutzer ja irgendwie Einfluss auf die Position haben. Da fallen mir folgende Möglichkeiten als Lösung ein, aber für jede auch direkt ein Gegenargument, deshalb bin ich z.Z. nicht sicher wie man das Problem lösen sollte:
1.
class sprite
{
public:
// standard getter/setter
void setPos(const vector<float>& aPos);
const vector<float>& getPos() const;
};
2.
class sprite
{
public:
// andere Namen
void move(const vector<float>& dir); // wobei man hier auch überlegen muss, ob move wirklich angebracht ist; denn move ist vom Namen her eher pos += dir statt pos = dir
const vector<float>& where() const;
};
3.
class sprite
{
public:
// setter als einfache Referenz
vector<float>& pos();
const vector<float>& pos() const;
};
1. ist standard, warum das hier schwer ist komm ich gleich zu
2. ist "moderner" aber differenzierter (nähert sich eher dem konzept der c++ std.bibl.)
3. ist flexibel aber enthält im Grunde keine Kapselung mehr (abgesehen von der const-überladung) und Validation (weshalb viele setter statt direkten Zugriff benutzen) ist auch nicht mehr möglich.
So, weshalb die Methode 1 "schwer" ist:
Man übergibt setPos gleich einen neuen Vektor, der die alte Position überschreibt. Manchmal will man ein Objekt aber z.b. nur in y-Richtung verschieben und die alten x- und z-Werte beibehalten. Das würde dann in so einem "Monster" gipfeln:
obj.setPos( obj.getPos().x, y, obj.getPos().z );
das würde ich einem Kunden nicht gern zumuten.
Um dem zu umgehen könnte man entweder eine neue Methode einbauen, wie setPosY() die nur y-Werte setzt. Dabei würde die Klasse aber schließlich von set-Methoden überfüllt werden, die nur auf den Member pos zugreifen
void setPos(const vector<float>& aPos);
void setPosX(float aX);
void setPosY(float aY);
void setPosZ(float aZ);
Eine weitere Mögl. wäre, so etwas wie eine move-Methode einzubauen, dann könnte man für x- und z-Koordinate einfach 0 übergeben (s.O: move meint vom ausdruck her "bewegen", also eine Vektoraddition, sonst müsste man es "moveTo" nennen, wäre dann aber wieder das gleiche wie setPos). Möchte man dabei allerdings die absolute Koordinate bewegen, müsste man wieder eine Differenz aus alter und neuer Koordinate bilden:
obj.move( 0, y - obj.getPos().y, 0 );
Ansonsten könnte man noch folgendermaßen argumentieren: Meine Klasse Vektor stellt sicherlich verschiedene Möglichkeiten bereit um die Position zu verschieben, ändern oder auch nur genau eine Koordinate zu verändern. Dann könnte man ja einfach eine Referenza auf pos zurückgeben, und den Benutzer mit den in vektor<> enthaltenen Funktionen arbeiten zu lassen. Das führt dann zu sowas wie
obj.pos().y = y
oder
obj.pos().y += y
etc., dies ist zwar flexibel und einfach, aber aus oben genannten Gründen für mich nicht möglich, da das ja einen Vollzugriff auf pos erlauben würde und dem Prinzip der Kapselung, der OOP und der Validation widerspricht (s.o.).
so, irgendwie zeigt sich da für mich keine "perfekte" Lösung. Das ganze mit dem Objekt sprite war nur ein Beispiel, würde man das abstrahieren käme man hierzu:
Wie erlaube ich möglichst nahe am Kapselungskonzept und an den Richtlinien der OOP in einer Klasse Zugriff auf ein Objekt, das in vielen (aber nicht allen) Eigenschaften/Wegen, die die Klasse dieses Objekts bereitstellt, manipuliert werden darf?
Ich hoffe ihr habt mein Problem verstanden, ich bin interessiert an allen möglichen Lösungsvorschlägen, wie ihr das in die Hand nehmen würdet (und warum ihr das so machen würdet).
Vielen Dank!
PS: ggf kann das Thema auch abgespalten werden