[OOP] richtig strukturieren...

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • [OOP] richtig strukturieren...

    Hallo Leute,
    bin in letzter Zeit ein wenig dran, mir die objektorientierte Programmierung reinzupfeifen, bin mir aber immer noch nicht sicher (und finde diesbezüglich auch irgendwie nichts), wie ein OOP System aussehen sollte. Da das natürlich für alles unterschiedlich sein kann hier mal ein Beispiel von mir für ein Browsergame (jaja, lacht nur...):

    Es gibt eine SQL Klasse 'connection', die die Datenbank steuert.

    Nun war meine Idee die folgende: Jede weitere Klasse ist Kindklasse von Connection und dient somit als Schnittstelle zur Datenbank, z.B.:

    class user extends connection {...}
    class character extends connection {...}
    class message extend connection {...}
    etc.

    Nun instantiiere ich zu Beginn des Scripts sämtliche Klassen, die ich gebrauchen könnte (user, character, party), wo auch schon mein Problem liegt.
    Das ganze scheint mir total Banane zu sein insbesondere da ich die Klassen nur auf einzelne Objekte beziehe (z.B. nur ein user) und ich somit mit diesen Klassen keine Übersicht aller Objekte hinbekomme (oder nur sehr aufwendig...).
    Nun dachte ich an eine Realisierung in der Art wie Javascript es hat, also statt:
    $user = new user($session_id());
    $character = new character($user->character);
    $character->name

    sowas:

    $user[$session_id()]->character->name

    wobei dann in der klasse user natürlich die unterklassen angelegt werden müssten...

    Wollte da mal die Meinung nach Sinn und Vorgehen bei sowas haben (auch allgemeiner), bzw. falls existent gerne auch Verweise auf entsprechende Tuts.
    Danke schonmal
    Zuletzt geändert von ZombieChe; 05.03.2007, 21:36.

  • #2
    Normalerweise macht man es mit der Datenbank-Klasse ganz gerne so, das sie als Singleton angelegt wird. So hast du lediglich eine Verbindung zur Datenbank (jede deiner Unterklassen hätte ja sonst eine eigene Verbindung) und du kannst aus jeder Klasse heraus darauf zugreifen.
    Deine User oder Character sind schonmal ein wenig verwirrend, denn was ist denn jetzt was? Für mich hört sich das vom Namen her so an, als sei beides das gleiche!
    Generell würde ich User, da sie ja lediglich Daten in sich tragen, als eine Unterklasse von ArrayObject anlegen und weitere Methoden, wie store() zum Speichern in der Datenbank usw. hinzufügen.
    Um dann Aktionen zum Erzeugen eines User durchführen zu können, kannst du dann entweder deinem Konstruktor die User-ID mitgeben und der User erstellt sich selbst, oder du baust dir eine Klasse UserManager oder soetwas, welche dir User erbauen kann. Diese Klasse hat dann eine Methode createUser( id ).

    Vielleicht hilft dir das ja schonmal weiter! Und du erklärst uns einmal den Unterschied zwischen User und Character!

    Kommentar


    • #3
      Re: [OOP] richtig strukturieren...

      Original geschrieben von ZombieChe
      Es gibt eine SQL Klasse 'connection', die die Datenbank steuert.

      Nun war meine Idee die folgende: Jede weitere Klasse ist Kindklasse von Connection und dient somit als Schnittstelle zur Datenbank, z.B.:
      Nee, das ist murks. Ein user ist keine connection.
      Ein user hat eine connection, mit der er arbeiten kann.
      Wenn du willst das zustände der objekte in der datenbank
      abgelegt werden können, dann könntest du eine abstrakte
      klasse DBStorable oder so anlegen. Diese klasse hat dann wieder
      eine datenbankverbindung und deklariert die abstrakten methoden
      store und load. Jede der kindklassen implementiert die beiden
      methoden so wie sie es brauchen.

      Bsp.:
      PHP-Code:
      abstract class DBStorable{
            protected 
      $db_connection;
            abstract protected function 
      store();
            abstract protected function 
      load();
      }

      class 
      User extends DBStorable{

      Damit hast du ein interface für die persistenz und jede
      klasse die es angeht hat durch ihre basisklasse eine verbindung
      zur datenbank.

      Nun instantiiere ich zu Beginn des Scripts sämtliche Klassen, die ich gebrauchen könnte (user, character, party), wo auch schon mein Problem liegt.
      Das ganze scheint mir total Banane zu sein insbesondere da ich die Klassen nur auf einzelne Objekte beziehe (z.B. nur ein user) und ich somit mit diesen Klassen keine Übersicht aller Objekte hinbekomme (oder nur sehr aufwendig...).
      Hier kommen statische methoden ins spiel.
      Beispielhaft die klasse user.

      PHP-Code:
      //die eigenschaften eines konkreten benutzers sind
      //hier mal ganz banal
      //Wenn du eine ORM-framework benutzt ist das viel einfacher
      class User{
           private 
      $name;
           private 
      $age;
           private 
      $id;
           public function 
      __construct($name,$age,$id){
                 
      $this->name $name;
                 
      $this->age $age;
                 
      $this->id $id;
           }
          static public function 
      find($id){
               
      $con  DB::getInstance();
               
      $res $con->query("SELECT name,age,id FROM `user`  WHERE id = ?"$id);
               if(
      $res){
                  return new 
      User($res['name'],$res['age'],$res['id']);
               }else{
                  return 
      null;
               }
          }
         
         static public function 
      find_all(){
              
      $con DB::getInstance();
              
      $res $con->query("SELECT * FROM user");
              
      $users = array();
              
              if(
      $res){
                 foreach(
      $res as $cur){
                     
      $users[]= new User($cur['name'],$cur['age'],$cur['id']);
                 }
             }
             return 
      $users;
         }
       
         
      //static public function find_by_name($name);

      Ich denke du weisst worauf es hinausläuft. Ein konkreter user
      wird durch eine instanz der klasse user modelliert. Der zugriff
      auf die user-tabelle wird durch die klasse und deren statische
      methoden modelliert.

      Hier sieht man wiederkehrende muster die man noch refaktorieren
      kann, aber das überlass ich dir.

      Als allgemeiner tipp. Es geht nur um mustererkennung. Wenn sich
      etwas wiederholt oder ähnlich aussieht, denke darüber nach ob
      man es abstrahieren könnte sodass man die muster wegkapseln
      kann und sich nicht ständig wiederholen muss. Wenn dir etwas
      zu kompliziert erscheint dann steige eine stufe höher in der abstraktion.
      Es gibt kein problem dass sich nicht durch einen zusätzlichen layer
      der indirektion lösen liesse.

      Achte darauf dass deine klasseintefaces so groß wie nötig und so
      klein wie möglich sind. Achte darauf dass jede klasse wirklich nur
      das tut wofür sie gedacht ist.

      Ich hoffe das hilft dir etwas.

      greets

      [EDIT]
      Jetzt ist user allerdings nicht mehr von DBStorable abgeleitet.
      Wie löst man das nun?
      Zuletzt geändert von closure; 06.03.2007, 09:10.
      (((call/cc call/cc) (lambda (x) x)) "Scheme just rocks! and Ruby is magic!")

      Kommentar


      • #4
        so, nun muss ich diesen Thread doch nochmal rauskramen *staubwegpust*. Vielen Dank erstmal für die Hilfe. Inzwischen hab ich mich ein wenig weiter mit OOP beschäftigt (z.B. auch mit Java), sodass ich nu auch alles nachvollziehen kann
        Allerdings stoße ich da noch auf ein Beziehungsproblem, das sich für mich als schwierig erweist.

        Folgende Realisierung möchte ich haben:

        Ein Benutzer (Klasse User) besitzt Städte (Klasse City).
        Eine Stadt besitzt einen Informationstext (z.B. die __toString() Methode) die folgende Daten enthält: Name - Bevölkerung - Besitzer

        Jetzt stoße ich auf das Problem, dass die Klasse City ja genau genommen keine Info über den Benutzer hat, da sie ja ohnehin nur innerhalb der Klasse User verwendet wird. Jetzt boten sich mir mehrere Möglichkeiten, die mich aber alle nicht sonderlich ansprechen:

        1. Ich mache die Benutzerinstanz global, um dann mit $user->name auf den Namen zuzugreifen.
        2. Ich übergebe der Stadt beim Instanzieren eine weitere Instanzvariable $owner, um darauf zuzugreifen.
        3. Ich rufe den Informationstext nicht aus der Klasse City, sondern aus der Klasse User auf (z.B. $user->printCityDescriptionOf($city_id) ), wodurch ich ja direkt Zugriff auf den Benutzernamen hätte.

        Aber:
        1. scheint mir nicht professionell, weil ich das Objekt ja auf eine Eben ziehe, wo es eigentlich nicht hingehört
        2. wird etwas umfangreich wenn ich der Stadt z.B noch Gebäude gebe und das selbe Spiel nochmal anfängt (oder noch andere Infos benötigt werden)
        3. scheint mir fehl am Platz zu sein und am Ende habe ich dann 50 Methode allein für Informationstexte in der Userklasse

        Ich hatte auch versucht das komplette Userobjekt zu übergeben, aber letztendlich führt das ja zu einer Rekursion beim Zugriff:
        $user->getStructure(1)->owner->getStructure(1)->owner->......


        Ich wär für eure Hilfe echt dankbar, da mich das ganze ziemlich auf die Palme bringt und ich mir dadurch die ganze OO versaue....

        Danke schonmal
        ZC

        Kommentar


        • #5
          1. Ich mache die Benutzerinstanz global, um dann mit $user->name auf den Namen zuzugreifen.
          Einbahnstrasse! Du nutzt hier die Einzigartigkeit des User Objekts aus. Wenn du gleichzeitig mehrere User-Instanzen hast, weiß keine Stadt welches X in $users[X] ihr Besitzer ist.
          Im Endeffekt machst du die Klasse User hintenrum zum Singleton.
          2. Ich übergebe der Stadt beim Instanzieren eine weitere Instanzvariable $owner, um darauf zuzugreifen.
          Ja so würde ich es machen.
          3. Ich rufe den Informationstext nicht aus der Klasse City, sondern aus der Klasse User auf (z.B. $user->printCityDescriptionOf($city_id) ), wodurch ich ja direkt Zugriff auf den Benutzernamen hätte.
          Damit hättest du das gleiche Problem wie bei 1. und außerdem fügst du Funktionalität ins User Objekt, die da nicht hingehört. Wenn man den Gedanken mal ganz weit überzieht, hat man am Ende einen omnipotenten User und alles andere sind nur taube Objekthülsen.

          Kommentar


          • #6
            okay, genau genommen handelte es sich in dem Fall, den ich meinte, tatsächlich um ein eimaliges Userobjekt, da es den eingeloggten Benutzer modelliert. Hatte ihn zu Beginn nicht mit dem Singleton Pattern generiert, da es eine abgeleitete Klasse von User ist und der Konstruktor nicht private sein durfte...naja, vielleicht sollte ich das noch ändern.

            Die Frage war ja eigentlich, ob es da nicht geschicktere Modellierungen gibt, da mir das "Durchschleifen" einer Information bis zum letzten Objekt sehr aufwenig vorkommt. z.B. folgender Baum:

            $user->city->district->building->room->person

            Wollte ich nun darstellen, welchem Benutzer die Person gehört, müsste ich den Namen des Benutzers bis zur Person durch alle Objekte mittragen. Möglich, aber ist das auch so üblich? Oder durchlauf ich hier ein Szenario, das es so ohnehin nie geben würde? Ich sollte echt mehr planen....

            Kommentar


            • #7
              $user->city->district->building->room->person ?
              Ich nehme an es geht mal wieder um ein Browsergame ...
              Im nächsten Level sind interstellare Hochzeiten möglich, was dich zu dieser Blüte treibt:
              $user->$universe->solarsystem->planet->continent->country
              ->fedstate->city->district->building->floor->room->person
              ->righthand->fingers[4]->putOn($ring)


              Du hast $user zum Universalobjekt gemacht. Und noch viel schlimmer, du modellierst alles streng hierarchisch.
              OOP ist aber was ganz anderes als objektrelationale DBS. Du kannst jede Art von Beziehung modellieren, mehr als nur is-a/has-a und is-related-to wie bei DBS. Das ist auch nötig, denn Daten sind tot, aber Objekte re-/agieren (Stichwort Observer).

              Wie wäre es denn hiermit?
              Die Stadt gehört dem User: $city->owner == $user
              Die Person gehört dem User: $person->master == $user
              Kein Hierarchie mehr. Die Person kann den Besitzer wechseln ohne in eine andere Stadt ziehen zu müssen.
              Zuletzt geändert von onemorenerd; 10.08.2007, 12:17.

              Kommentar

              Lädt...
              X