php-resource



Zurück   PHP-Scripte PHP-Tutorials PHP-Jobs und vieles mehr > Entwicklung > PHP Developer Forum
 

Login

 
eingeloggt bleiben
star Jetzt registrieren   star Passwort vergessen
 

 

 


PHP Developer Forum Hier habt ihr die Möglichkeit, eure Skriptprobleme mit anderen Anwendern zu diskutieren. Seid so fair und beantwortet auch Fragen von anderen Anwendern. Dieses Forum ist sowohl für ANFÄNGER als auch für PHP-Profis! Fragen zu Laravel, YII oder anderen PHP-Frameworks.

Antwort
 
LinkBack (1) Themen-Optionen Thema bewerten
  1 links from elsewhere to this Post. Click to view. #1 (permalink)  
Alt 02-04-2012, 11:23
jack88
 Registrierter Benutzer
Links : Onlinestatus : jack88 ist offline
Registriert seit: Mar 2012
Beiträge: 24
jack88 befindet sich auf einem aufstrebenden Ast
Standard OOP: Assoziation zwischen zwei Klassen

Hallo,

ich habe mal wieder eine Verständnisfrage zu OOP

Diesmal geht es um die konkrete Implementierung einer Assoziation zwischen zwei Klassen Kunde und Kundenliste.

Kundenliste -> Kunde (Kundenliste enthält Kunde)


Mal angenommen ich habe eine Klasse Kunde:

PHP-Code:
class Kunde {
      protected 
$kundennummer null;
      protected 
$name null;
      protected 
$alter null;
      protected 
$gesundheit null;
      
      public function 
__construct($kundennummer) {
          
// Kundendaten aus DB Laden und Eigenschaften setzen
          // SELECT .... FROM Kunde WHERE id=$kundenummer
          
          
$this->kundenummer $db_row["kundenummer"];
          
$this->name $db_row["name"];
          
// usw...
      
}
      
      public function 
getLebenserwartung() {
          
//Algorithms zur Berechnung der Lebenserwartung
          // Lebenserwartung wird nicht in der DB gespeichert (dient nur der Veranschaulichung)
          
return 100-($this->alter*$this->gesundheit);
      }
  } 
(die Beispiele sind bewusst sehr einfach gehalten und dienen wirklich nur der Veranschaulichung des Problems)

Nun kann ich bequem ein neues Kundenobjekt erzeugen und mir z.B. die Lebenserwartung anzeigen lassen:

PHP-Code:
$ulli = new Kunde(10);
  echo 
$ulli->getLebenserwartung(); 
Jetzt möchte ich noch eine weitere Klasse erstellen mit der sich bestimmte Daten mehrerer Kunden in einer Tabelle/Liste darstellen lassen.
Lösung 1

PHP-Code:
class Kundenliste {
      private 
$sqlResult null;
  
      
punblic function __construct($kdnr_von,$kdnr_bis) {
          
//select-abfrage auf die Kundendaten z.B;
          // SELECT * FROM Kunde WHERE id>=$kdnr_von && id<=$kdnr_bis
          
$this->sqlResult $ergebnisskennung_der_abfrage;
      }
  
      public function 
display() {
          foreach(
$this->sqlResult as $row) {
              
$kunde = new Kunde($row["kundenummer"]);
              echo 
$kunde->name.", Lebenserwartung: ".$kunde->getLebenserwartung();
          }
      }
  } 
Bei dieser Lösung wird in der Methode display() jedes mal ein neues Kundenobjekt erzeugt.

Vorteil:
ich arbeite mit einem Kundenobjekt und kann direkt auf seine Eigenschaften und Methoden zugreifen. Das ist sehr bequem und ich muss mich um die Implementierung der Kunden-Methoden nicht kümmern

Nachteil:
Jedes mal wenn ich ein neues Kundenobjekt erzeuge greife ich auf die DB zu um seine Daten zu holen. Das ist in diesem Fall sehr ineffizient und verursacht einen unnötigen DB-Overhead.


Lösung 2:

PHP-Code:
class Kundenliste {
      private 
$sqlResult null;
      
      
punblic function __construct($kdnr_von,$kdnr_bis) {
          
//select-abfrage auf die Kundendaten z.B;
          // SELECT .... FROM Kunde WHERE id>=$kdnr_von && id<=$kdnr_bis
          
$this->sqlResult $ergebnisskennung_der_abfrage;
      }
      
      public function 
display() {
          foreach(
$this->sqlResult as $row) {
              echo 
$row["name"].", Lebenserwartung: ".$this->getLebenserwartung($row["alter"],$row["gesundheit"]);
          }
      }
      
      protected function  
getLebenserwartung($alter,$gesundheit) {
          return 
100-($alter*$gesundheit);
      }
  } 
Vorteil:
Der DB-Overhead ist weg. Die Methode display() ist somit effizienter als bei Lösung 1

Nachteil:
Ich kann nicht mehr auf die Methoden und Eigenschaften des Kunden bequem über ein Kundenobjekt zugreifen. Schlimmer noch, ich muss die Methoden des Kundenobjektes die ich für die Darstellung in der Liste benötige neu implementieren. Jede Änderungen in der Klasse Kunde hat somit auch eine entsprechende Anpassung in der Klasse Kundenliste zur Folge.


Beide Lösungsansätze haben meiner Meinung nach zu große Nachteile und sind nicht wirklich zufriedenstellend. Wie macht man es in OOP aber richtig? Wie aggregiert oder injiziert man ein Kundenobjekt in die Klasse Kundenliste ohne dabei zusätzlich den DB-Overhead zu verursachen und ist es überhaupt der richtige Ansatz das Problem so zu lösen, oder würde man es mit OOP ganz anders angehen?


Eine Idee hätte ich da noch, wenn der Konstruktor von Kunde wie folgt ergänz wird:

PHP-Code:
    public function __construct($kundennummer) {
          if(
$kundennummer) {
              
// Kundendaten aus DB Laden und Eigenschaften setzen
              // SELECT .... FROM Kunde WHERE id=$kundenummer
          
              
$this->kundenummer $DB["kundenummer"];
              
// usw...            
          
}
      } 
dann ließe sich auch ein „leeres“ Kundenobjekt so eine Art Prototyp erstellen, der mit entsprechenden setter-Methoden nachträglich in der Klasse Kundenliste mit Daten gefüllt werden könnte:


PHP-Code:
    public function display() {
          foreach(
$this->sqlResult as $row) {
              
$kunde = new Kunde(false);
              
$kunde->setName($row["name"]);
              
$kunde->setAlter($row["alter"]);
              
// usw 
              
echo $kunde->name.", Lebenserwartung: ".$kunde->getLebenserwartung();
          }
      } 
Ok, damit könnte man den DB-Overhead komplett vermeiden und hätte gleichzeitig den Vorteil, daß man bequem mit dem Kundenobjekt arbeiten könnte, allerdings müsste man dann sicherstellen, daß man dem Kundenobjekt auch wirklich alle Daten übergibt, das wiederum würde bei Umfangreichen Objekten mit vielen Eigenschaften schnell relativ aufwendig werden und könnte leicht zu inkonsistenten Objekten führen.

Was wäre bei dieser Problemstellung nun die richtige Vorgehensweise im Sinne des objektorientierten Designs?

jack

Geändert von jack88 (02-04-2012 um 11:26 Uhr)
Mit Zitat antworten
  #2 (permalink)  
Alt 02-04-2012, 12:00
litterauspirna
 Registrierter Benutzer
Links : Onlinestatus : litterauspirna ist offline
Registriert seit: Nov 2007
Beiträge: 364
litterauspirna ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Hallo,

schau dir mal das MVC Pattern an, ich weiß zwar nicht wie weit du bist, aber nimmt dir einges ab und vor allem du schaffst dir dadurch eine bessere Übersicht.

So bekommst über dein Model und / oder einen Mapper dein Datenmodel für die Darstellung. Weitere Logik übernimmt der Controller und am Ende folgt die Ausgabe über die View.

Deine beiden Lösungsvarianten gefallen mir persönlich nicht, weil in beiden zuviel zusammengebracht wird was nicht zusammengehört.

Wenn du für jeden User schon ein eigenes Objekt erzeugen willst, dann mache das nicht in der UserList Klasse fest, sondern von außen in die Klasse injizieren. Stichwort Dependency Injection.

Gruß Litter
__________________
Aus dem Dynamo Lande kommen wir. Trinken immer reichlich kühles Bier. Und dann sind wir alle voll, die Stimmung ist so toll. Aus dem Dynamo Lande kommen wir.
http://www.lit-web.de
Mit Zitat antworten
  #3 (permalink)  
Alt 02-04-2012, 12:23
jack88
 Registrierter Benutzer
Links : Onlinestatus : jack88 ist offline
Registriert seit: Mar 2012
Beiträge: 24
jack88 befindet sich auf einem aufstrebenden Ast
Standard

Hej, das ging ja wirklich schnell :-)

Wie gesagt, die Beispiele dienen nur der Veranschaulichung der eigentlichen Problematik.

Mit MVC Pattern werde ich mich noch beschäftigen, aber da geht es in erster Line um die Trennung von Datenschicht, Präsentationsschicht und Business-Logik.

Mir geht es hier sozusagen nur um die Basics des objektorientierten Designs.

Zitat:
Wenn du für jeden User schon ein eigenes Objekt erzeugen willst, dann mache das nicht in der UserList Klasse fest, sondern von außen in die Klasse injizieren. Stichwort Dependency Injection.

Dependency Injection ist mir bekannt, aber wie würdest Du das bei der Klasse Kundenliste einsetzen und welchen Vorteil sollte das haben? Vielleicht könntest Du das an einem kurzen Beispiel veranschaulichen?
Mit Zitat antworten
  #4 (permalink)  
Alt 02-04-2012, 17:03
hostbar_danny
 Registrierter Benutzer
Links : Onlinestatus : hostbar_danny ist offline
Registriert seit: Feb 2011
Beiträge: 66
hostbar_danny befindet sich auf einem aufstrebenden Ast
Standard

Du möchtest Objekte (hier im OOP Kontext gesprochen) in einer relationalen Datenbank abbilden. Das ganze nennt sich ORM ( https://de.wikipedia.org/wiki/Objekt...nale_Abbildung ). Wenn du eine eigene Lösung entwickeln möchtest wirst du unter dem Begriff sicherlich einige Anhaltspunkte finden. Wenn du auf eine sehr gute und meines Erachtens quasi PHP Standard (im Bezug auf ORM in PHP) Lösung zurückgreifen möchtest sehe dir Doctrine 2 ( Welcome to the Doctrine Project &mdash; Doctrine-Project ) an.

Gruß Danny
Mit Zitat antworten
  #5 (permalink)  
Alt 02-04-2012, 17:54
jack88
 Registrierter Benutzer
Links : Onlinestatus : jack88 ist offline
Registriert seit: Mar 2012
Beiträge: 24
jack88 befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Du möchtest Objekte (hier im OOP Kontext gesprochen) in einer relationalen Datenbank abbilden.
Nein, das möchte ich nicht, auch wenn ich das Thema sehr spannend finde ;-)

Wenn ich das Problem prozedural, also ohne Objekte und Klassen lösen sollte, dann würde ich in etwa wie folgt vorgehen:

PHP-Code:
// KUNDE
function getKundeById($id) {
    
// SELECT .... FROM Kunde WHERE id=$id
    // Array mit allen Kundendaten zurückliefern
    
return $db_row;


// weitere Kundenfunktionen wie z.B. Berechnung der Lebenserwartung
function getLebenserwartung($alter,$gesundheit) {
          return 
100-($alter*$gesundheit);
      }     


// KUNDENLISTE      
function displayKundenliste($id_von,$id_bis) {
    
// SELECT .... FROM Kunde WHERE id>=$id_von && id<=$id_bis
    
foreach($sqlResult as $row) {
        echo 
$row["name"].", Lebenserwartung: ".getLebenserwartung($row["alter"],$row["gesundheit"]);
    }

Nun möchte ich es wie gesagt anstatt prozedural objektorientiert abbilden und frage mich, wie dieses einfache Beispiel mit Klassen und Objekten vernünftig umgesetzt werden kann?

gruß jack
Mit Zitat antworten
  #6 (permalink)  
Alt 03-04-2012, 13:22
jack88
 Registrierter Benutzer
Links : Onlinestatus : jack88 ist offline
Registriert seit: Mar 2012
Beiträge: 24
jack88 befindet sich auf einem aufstrebenden Ast
Standard

Leider komme ich bei dem beschriebenen Problem nicht weiter. Bei meinen Recherchen bin ich in diesem Zusammenhang über die Begriffe Datenklasse und Modell-Klasse gestolpert.

Finde dazu allerdings keine brauchbaren Informationen. Vielleicht kennt sich ja jemand mit dem Thema aus und wäre so nett es hier kurz zu erklären was es damit auf sich hat?

Vielen Dank im Voraus.
jack
Mit Zitat antworten
  #7 (permalink)  
Alt 03-04-2012, 14:39
litterauspirna
 Registrierter Benutzer
Links : Onlinestatus : litterauspirna ist offline
Registriert seit: Nov 2007
Beiträge: 364
litterauspirna ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Naja eine Model Klasse ist denke ich einfach ein Model im MVC.

Aber eine solche Klasse oder Klassen kannst du auch unabhängig des Patterns schreiben. Daten kannst du eben aus der Persistens Schicht oder auch der Präsentationsschicht holen und einer Model Klasse (oder Datenklasse) übergeben.

Wichtig dabei ist das die Datenklasse nichts von seiner Datenquelle wissen sollte, weil du dich da in der Flexibilität einschränkst. Du kannst deine Modelklassen von verschiedenen Datenlayern erben lassen. So zum Beipiel kann ein Model mit XML, Json oder einer Datenbank kommunizieren bzw. da seine Daten her holen oder dahin speichern (um mal auf der Webebene zu bleiben).

Man kann das ganze so ausbauen das Models eben nur die reine Datenstruktur beinhalten oder darstellen und man die handelnden Methoden zum speichern etc. eben in einen Mapper packt.

Es gibt viele Ansätze in der Richtung, wenn man aus dem Web ausbricht und Serverapplikationen schreibt die dann auf Hardware etc. zugreifen oder die Master File Table bei Windows kommen ja wieder andere Datenlayer zustande.

Also kurz zusammen gefasst, schreibe dir Datenlayer die dafür geschaffen sind mit gewissen speziellen Datenquellen zu komminuzieren und lasse deine Modelklassen je nach bedarf von diesen Layern erben. Brauchst du in einem Model mehrere Layer dann schaffe dir Methoden die deine Layerklassen zur Benuzung dem Model hinzufügen.

Gruß der Litter
__________________
Aus dem Dynamo Lande kommen wir. Trinken immer reichlich kühles Bier. Und dann sind wir alle voll, die Stimmung ist so toll. Aus dem Dynamo Lande kommen wir.
http://www.lit-web.de
Mit Zitat antworten
  #8 (permalink)  
Alt 04-04-2012, 12:00
Benutzerbild von ApoY2k ApoY2k
 Registrierter Benutzer
Links : Onlinestatus : ApoY2k ist offline
Registriert seit: Nov 2006
Beiträge: 359
ApoY2k befindet sich auf einem aufstrebenden Ast
ApoY2k eine Nachricht über ICQ schicken ApoY2k eine Nachricht über Skype™ schicken
Standard

Klassen sollen laut SOLID nur exakt eine Verantwortung haben.

In deinem Fall ist die Verantwortung der Klasse "UserList", eine Liste von Usern zu verwalten. Das heißt, dass diese Klasse ausschließlich zur Verwaltung von Usern da ist, und nicht zur ERSTELLUNG von User-Objekten.

Wie litterauspirna schon gesagt hat, musst du für "richtiges" (Anführungszeichen!) OOP die User-Objekte von außen in deine Userlist geben.

Das sähe dann ugf. so aus:

PHP-Code:
$user = new Kunde(10);
$userList $new Kundenliste();
$userList->addUser($user); 
Intern verwaltet die Kundenliste ein Array, in dem alle User-Objekte gespeichert werden. Auf diesem Array kannst du dann alle Aktionen ausführen. Z.b.:

PHP-Code:
foreach ($userList->getUsers() as $user) {
    echo 
$user->getLebenserwartung();

Weiterhin sehe ich in deinem Code ein weiteres Problem, das auch auf das Prinzip der "single responsibility" zurückzuführen ist. Deine User-Klasse baut eine Datenbankverbindung auf.

Das gehört nicht in die Verantwortung einer User-Klasse. Diese sollte ausschließlich den Rahmen repräsentieren, die einen user darstellt.

Um User aus der Datenbank zu erstellen, solltest du besser eine neue Klasse erstellen, die ausschließlich dazu da ist, User zu erstellen - eine UserFactory.

Diese Klasse könnte dann z.B. so aussehen:

PHP-Code:
class UserFactory {
    public function 
createUserFromDatabase($userId) {
        
$user = new User();
        
// Daten aus der Datenbank suchen und das Userobjekt damit füllen
        
return $user;
    }

Mit diesem Aufbau schaffst du eine perfekte Trennung der Zuständigkeiten der Klassen. Die UserList macht nur, was der Name sagt: Liste von Usern verwalten. Der User ist nur eine leere Hülle, die mit Daten gefüllt werden kann und die UserFactory macht nichts anderes außer user aus der Datenbank zu generieren.

Das erleichtert die Wartung und Entwicklung deiner Klassen erheblich, da du genau weißt, welche Klasse was macht. Und in der Verwendung ist es auch wesentlich eindeutiger, was passiert:

PHP-Code:
$userFactory = new UserFactory();
$user $userFactory->createUserFromDatabase(1);
$userList = new UserList();
$userList->addUser($user);

foreach (
$userList->getUsers() as $user) {
    echo 
$user->getLebenserwartung();

__________________
This is what happens when an unstoppable force meets an immovable object.

Geändert von ApoY2k (04-04-2012 um 12:02 Uhr)
Mit Zitat antworten
  #9 (permalink)  
Alt 21-04-2012, 09:27
jack88
 Registrierter Benutzer
Links : Onlinestatus : jack88 ist offline
Registriert seit: Mar 2012
Beiträge: 24
jack88 befindet sich auf einem aufstrebenden Ast
Standard

Vielen Dank nochmals für alle Antworten.

Wenn ich Die Userliste wie von ApoY2k beschrieben mit einer UserFactory generiere, dann banötige ich ich für jeden User genau eine Sql-Abfrage, ist das nicht sehr ineffizient?

Um eine Liste zur erstellen würde ich normalerweise wie folgt vorgehen:

Code:
// SELECT .... FROM Kunde WHERE id<100
foreach($sqlResult as $row) {
    // erstelle Userliste   
 }
Die UserFactory-Lösung entspricht imho vielmehr diesem Ansatz:

Code:
for($i=0;$i<100;$i++) {
    // SELECT .... FROM Kunde WHERE id=$i
    // erstelle UserListe
}
oder mache ich hier irgendwo einen Denkfehler?
gruß
jack
Mit Zitat antworten
  #10 (permalink)  
Alt 21-04-2012, 09:51
PicdumpR
 Registrierter Benutzer
Links : Onlinestatus : PicdumpR ist offline
Registriert seit: Apr 2012
Beiträge: 6
PicdumpR befindet sich auf einem aufstrebenden Ast
Standard

So wie er die UserFactory geschrieben hat, ja.

Aber es spricht ja nichts dagegen, eine entsprechende Methode zum erstellen ALLER user zu schreiben, oder eine Methode die den User durch übergeben eines mysql-result-sets erstellt.

z.B.:
PHP-Code:
public function createUserList() {
    
// MySQL-Query für alle user
    // Schleife über alle Ergebnisse und user erstellen


Geändert von PicdumpR (21-04-2012 um 10:13 Uhr)
Mit Zitat antworten
Antwort

Lesezeichen


LinkBacks (?)
LinkBack to this Thread: https://www.php-resource.de/forum/php-developer-forum/102824-oop-assoziation-zwischen-zwei-klassen.html
Erstellt von For Type Datum
php assotiative klassen - WEB.DE - Web-Suche This thread Refback 04-10-2013 23:30

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
[OOP] Statische Klassen... GELight PHP Developer Forum 8 24-02-2009 10:43
Problem mit Eigenschaftenübergabe zwischen Klassen (vererbung? ) Breezzer PHP Developer Forum 4 24-12-2005 12:20
Klassen (OOP) bweichel PHP Developer Forum 4 17-11-2004 17:22
[OOP] Klassen Problem MTCook PHP Developer Forum 11 14-11-2004 19:48
[OOP]klassen design ShoAn PHP Developer Forum 1 28-08-2004 17:52

Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an


PHP News

ebiz-trader 7.5.0 mit PHP7 Unterstützung veröffentlicht
ebiz-trader 7.5.0 mit PHP7 Unterstützung veröffentlichtDie bekannte Marktplatzsoftware ebiz-trader ist in der Version 7.5.0 veröffentlicht worden.

28.05.2018 | Berni

Wissensbestand in Unternehmen
Wissensbestand in UnternehmenLebenslanges Lernen und Weiterbilden sichert Wissensbestand in Unternehmen

25.05.2018 | Berni


 

Aktuelle PHP Scripte

ADSMAN V3 - Werbe-Manager ansehen ADSMAN V3 - Werbe-Manager

ADSMAN V3 - mehr als nur ein Bannermanager! Banner, Textanzeigen und PagePeel Manager! Mit ADSMAN PRO haben Sie die Marketinglösung für eine effektive und effiziente Werbeschaltung mit messbaren Ergebnissen. Unterstützt werden Bannerformate in beliebi

25.10.2018 virtualsystem | Kategorie: PHP/ Bannerverwaltung
PHP News und Artikel Script V2

News schreiben, verwalten, veröffentlichen. Dies ist jetzt mit dem neuen PHP News & Artikel System von virtualsystem.de noch einfacher. Die integrierte Multi-User-Funktion und der WYSIWYG-Editor (MS-Office ähnliche Bedienung) ermöglichen...

25.10.2018 virtualsystem | Kategorie: PHP/ News
Top-Side Guestbook

Gästebuch auf Textbasis (kein MySQL nötig) mit Smilies, Ip Sperre (Zeit selbst einstellbar), Spamschutz, Captcha (Code-Eingabe), BB-Code, Hitcounter, Löschfunktion, Editierfunktion, Kommentarfunktion, Kürzung langer Wörter, Seiten- bzw. Blätterfunktion, V

22.10.2018 webmaster10 | Kategorie: PHP/ Gaestebuch
 Alle PHP Scripte anzeigen

Alle Zeitangaben in WEZ +2. Es ist jetzt 17:48 Uhr.