Tải bản đầy đủ (.pdf) (30 trang)

PHP – Endlich objektorientiert- P10

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (561.27 KB, 30 trang )

4 – PHP objektorientiert
240
Die zweite Klasse, die von der Person abgeleitet werden soll, ist die Klasse der Mitarbei-
ter. Dabei wird in gleicher Weise wie bei der Kundenklasse vorgegangen. Nur die für
einen Mitarbeiter typischen Eigenschaften werden auch in der Mitarbeiterklasse festge-
halten.
Sie erkennen auch, dass alle Eigenschaften, die Mitarbeiter und Kunden gemeinsam
haben, ausschließlich in der Personenklasse gespeichert und verwaltet werden. Auf
diese Weise wird doppelter Quellcode verhindert und die Wartbarkeit der Anwendung
verbessert.
Sowohl der Mitarbeiter als auch der Kunde verfügen über die Eigenschaft $id. Wenn alle
konkreten Personen über eine ID verfügen, wieso wird diese ID dann nicht in die Ober-
public function __construct($id,$name,$vorname,$strasse,$plz,$ort){
parent::__construct($name,$vorname,$strasse,$plz,$ort);
$this->id=$id;
}
public function getID(){
return $this->id;
}
}
?>
<?php
class Mitarbeiter extends Person{
private $id; private $tarifGruppe;
private $firmenEintritt;
public function __construct($id,$name,$vorname,$strasse,$plz,$ort,
$tarifGruppe,$firmenEintritt){
parent::__construct($name,$vorname,$strasse,$plz,$ort);
$this->id=$id; $this->tarifGruppe=$tarifGruppe;
$this->firmenEintritt=$firmenEintritt;
}


public function getID(){
return $this->id;
}
}
?>
Listing 4.26: Die abgeleitete konkrete Klasse „Mitarbeiter“
Listing 4.25: Die abgeleitete konkrete Klasse „Kunde“ (Forts.)
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Realisierung von Klassengeflechten
PHP – Endlich objektorientiert 241
klasse ausgelagert? In PHP ist dies durchaus eine Designalternative, da der Datentyp
einer Eigenschaft nicht im Vorfeld festgelegt werden muss. Es können jedoch auch hier
Probleme auftreten, wenn man in einer Set-Methode die Gültigkeit einer ID prüfen muss.
Denn der Identifikator kann bei einem Kunden völlig anders aufgebaut sein als bei
einem Mitarbeiter. Ein Lösungsansatz würde für PHP darin bestehen, die Eigenschaft $id
zentral für den Kunden protected anstatt private zu definieren. Damit könnten auch
Methoden der Unterklasse direkt auf die Eigenschaft zugreifen. Im zweiten Schritt könn-
ten dann die Set-Methoden des Kunden und des Mitarbeiters mit den entsprechenden
Prüfungen überschrieben werden. Wie man Methoden überschreibt, wird im nächsten
Beispiel erläutert.
In Listing 4.27 werden zunächst die drei erzeugten Klassen getestet. Es werden ein
Kunde und ein Mitarbeiter erzeugt. Weil beide auch Personen sind, besitzen sie die
Methode getAnschrift(), die in beiden Fällen aufgerufen wird. Abschließend wird test-
weise der PHP-Befehl get_parent_class auf der Referenz des Mitarbeiterobjekts angewen-
det. Sie gibt den Namen der Oberklasse des Mitarbeiters, also Person zurück.
Die Ausgabe der Testklasse lautet wie erwartet:
Frank Dopatka
Hauptstrasse 4
51580 Reichshof
Ulli Streber

Sackgasse 2
12234 Berlin
Person
Im zweiten Beispiel der Vererbung wird die Tierhierarchie aus dem dritten Kapitel
umgesetzt. Dort wurden im objektorientierten Design die Klassen aus Abbildung 4.5
ermittelt.
<?php require_once("classloader.inc.php"); ?>
<html><body>
<?php
$a=new Kunde(1,'Frank','Dopatka','Hauptstrasse 4',51580,'Reichshof');
echo $a->getAnschrift();
$b=new Mitarbeiter('E34','Ulli','Streber','Sackgasse 2',12234,'Berlin',
'TvöD13','31.01.2008');
echo $b->getAnschrift();
echo get_parent_class($b);
?>
</body></html>
Listing 4.27: Testklasse der Vererbung
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
4 – PHP objektorientiert
242
Die abstrakte Klasse Tier hat eine Eigenschaft name, die als protected deklariert ist. Somit
kann der Zugriff für abgeleitete Klassen wie auf eine public-deklarierte Eigenschaft erfol-
gen.
Zusätzlich dazu ist auch die Methode gibLaut() im Tier laut der Definition im Klassendia-
gramm der UML abstrakt definiert. Man möchte also, dass jedes konkrete Tier Laut
geben kann. Wie dieser Laut jedoch aussieht, hängt von dem konkreten Tier ab.
Abgeleitet von der Tierklasse werden die Klassen Hund und Katze. Sie implementieren das
Lautgeben und zusätzlich noch die eigenen Methoden bellen() und miauen(). Jemand, der
einen Hund verwaltet, möchte den konkreten Laut unter Umständen direkt abfragen.

Zusätzlich ist eine Dogge ein spezieller Hund. Er kann besonders gut beißen und bietet
dies als eigene Methode an.
Abbildung 4.5: Klassendiagramm der Tierhierarchie
Listing 4.28 zeigt die Umsetzung der Tierklasse in PHP 5. Beachten Sie die Syntax der
abstrakten Methode gibLaut().
<?php
abstract class Tier{
protected $name;
Listing 4.28: Die abstrakte Klasse „Tier“ mit abstrakter Methode „gibLaut“
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Realisierung von Klassengeflechten
PHP – Endlich objektorientiert 243
Im nächsten Schritt wird die Katze modelliert, die ein Tier ist. Im Konstruktor besteht die
Möglichkeit, die Eigenschaft name direkt zu setzen. Darauf wird jedoch verzichtet und
stattdessen der Konstruktor der Oberklasse aufgerufen. Dort könnten zukünftig noch
weitere Initialisierungen vorgenommen werden, die auch für ein Katzenobjekt von
Bedeutung wären.
Neben der Bereitstellung der Methode miauen() ist die Implementierung der Methode
gibLaut() zu nennen. Die Methodendefinition muss genauso lauten wie in der Oberklasse
bis auf das fehlende Schlüsselwort abstract. Dadurch, dass diese Methode nun realisiert
wurde, können konkrete Objekte der Klasse angelegt werden.
Die Implementierung der Hundeklasse erfolgt in Listing 4.30 analog zur Katzenklasse.
public function __construct($name){
$this->name=$name;
}
public function getName(){
return $this->name;
}
abstract public function gibLaut();
}

?>
<?php
class Katze extends Tier{
public function __construct($name){
parent::__construct($name);
}
public function gibLaut(){
return $this->miauen();
}
public function miauen(){
return 'miau';
}
}
?>
Listing 4.29: Die abgeleitete Klasse „Katze“
Listing 4.28: Die abstrakte Klasse „Tier“ mit abstrakter Methode „gibLaut“ (Forts.)
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
4 – PHP objektorientiert
244
Von der Hundeklasse wird wiederum die Dogge als spezieller Hund abgeleitet. Da der
Hund bereits das Lautgeben implementiert, ist dies bei der Dogge nicht zwingend nötig.
Der Laut könnte natürlich durch ein Überschreiben der Methode mit identischer Defini-
tion public function gibLaut() neu definiert werden. Stattdessen wird die Methode get-
Name() bei der Dogge im Vergleich zum Tier neu definiert. Zusätzlich wird die neue
Methode beissen() definiert.
<?php
class Hund extends Tier{
public function __construct($name){
parent::__construct($name);
}

public function gibLaut(){
return $this->bellen();
}
public function bellen(){
return 'wow';
}
}
?>
Listing 4.30: Die abgeleitete Klasse „Hund“
<?php
class Dogge extends Hund{
public function __construct($name){
parent::__construct($name);
}
public function beissen(){
return 'grrr...';
}
public function getName(){
return $this->name.' die Dogge.';
}
}
?>
Listing 4.31: Die Dogge als spezieller Hund
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Realisierung von Klassengeflechten
PHP – Endlich objektorientiert 245
Der Test der Tierklassen erfolgt in Listing 4.32. Dabei wird ein Datenfeld angelegt, das
mit einer Katze und einer Dogge gefüllt wird. Beide geben ihren Namen aus, dann beißt
die Dogge einmal zu. Da die Dogge die Methode getName() neu definiert hat, wird die
neue Methode ausgeführt.

Anschließend soll jedes Tier im Datenfeld einen Laut von sich geben. Dazu wird das Feld
in einer Schleife durchlaufen. Dies ist natürlich besonders bei großen Feldern von Inter-
esse. Mit instanceof sollte noch eine zusätzliche Typprüfung durchgeführt werden, ob es
sich bei den Elementen des Feldes wirklich um Tiere handelt.
Zum Abschluss wird versucht, jedes Tier im Datenfeld zum Miauen zu bringen. Bei der
Dogge sollte dies problematisch werden.
Die Ausgabe ist auch hier erwartungsgemäß. Interessant ist auch die Fehlermeldung,
dass eine Dogge nicht miauen kann.
Nicki
Hasso die Dogge.
grrr...
miau
wow
miau
Fatal error: Call to undefined method Dogge::miauen() in ...
<?php require_once("classloader.inc.php"); ?>
<html><body>
<?php
$zoo=Array();
$zoo[0]=new Katze('Nicki');
echo $zoo[0]->getName().'<br>';
$zoo[1]=new Dogge('Hasso');
echo $zoo[1]->getName().'<br>';
echo $zoo[1]->beissen().'<br>';
for ($i=0;$i<2;$i++){
echo $zoo[$i]->gibLaut().'<br>';
}
for ($i=0;$i<2;$i++){
echo $zoo[$i]->miauen().'<br>';
}

?>
</body></html>
Listing 4.32: Testklasse für verschiedene Tiere
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
4 – PHP objektorientiert
246
4.2.2 Aufbau von Bekanntschaften: Assoziationen
Die Vererbung ist eine statische Abhängigkeit von Klassen, die zur Entwicklungszeit
festgelegt wird. Die Bekanntschaft von Objekten untereinander entsteht jedoch erst zur
Laufzeit. Nachdem ein Objekt ein anderes Objekt kennt, kann es Methoden auf dem
bekannten Objekt ausführen.
Als Beispiel wird die Beziehung einer Rechnungsposition zu einem Artikel verwendet.
Das Klassendiagramm der Abbildung 4.6 gibt dabei die Eigenschaften beider Klassen
vor. Aus Sicht des Artikels ist die Bindung sehr lose; ein Artikel kennt keine Rechnungs-
positionen. Er kann aber auf vielen Rechnungspositionen enthalten sein.
Eine Rechnungsposition kennt stets genau einen Artikel, der in einer gewissen Menge
eingekauft werden soll. Diese Abhängigkeit besteht bereits beim Erstellen der Rech-
nungsposition. Zusätzlich wird der Einzelpreis des Artikels und ggf. ein Rabatt auf die
jeweilige Rechnungsposition festgehalten.
Abbildung 4.6: Beziehung zwischen einer Rechnungsposition und einem Artikel
Listing 4.33 zeigt die Implementierung einer Rechnungsposition. Der Artikel ist dabei
eine Eigenschaft der Rechnungsposition und wird als Referenz im Konstruktor überge-
ben. Der Einzelpreis der Rechnungsposition wird aus dem Verkaufspreis des Artikels
ermittelt. Außerdem werden dir typischen Get-Methoden implementiert. Der Gesamt-
preis ist keine eigene Eigenschaft, sondern wird aus den existierenden Eigenschaften
unter Berücksichtigung des optionalen Rabatts auf die Rechnungsposition sowie der
Mehrwertsteuer aus dem Artikel berechnet.
<?php
class Rechnungsposition{
private $artikel; private $menge; private $ep; private $rabatt; // %

public function __construct($artikel,$menge,$rabatt){
$this->artikel=$artikel; $this->menge=$menge;
$this->ep=$artikel->getVK(); $this->rabatt=$rabatt;
}
public function getArtikel(){
Listing 4.33: Die Klasse „Rechnungsposition“
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Realisierung von Klassengeflechten
PHP – Endlich objektorientiert 247
Die in Listing 4.34 implementierte Artikelklasse hat keine Besonderheiten, sie implemen-
tiert lediglich die aus dem Klassendiagramm geforderten Eigenschaften und bietet Get-
Methoden dazu an.
Abbildung 4.7 zeigt nun ein Objektdiagramm des kleinen Testprogramms, das in Listing
4.33 vorgestellt wird. Da das Objektdiagramm ein konkretes Beispiel aus der objektorien-
tierten Analyse bildet, aus dem die Klassendiagramme erst abgeleitet werden (Kap. 3),
muss dieses Beispiel jetzt nachgebildet werden können.
return $this->artikel;
}
...
public function getGesamtpreis(){
return (($this->ep)*($this->menge))*(1-($this->rabatt)/100)*
(1+$this->artikel->getMwST()/100);
}
}
?>
<?php
class Artikel{
private $id; private $name; private $beschreibung;
private $ek; private $vk; private $mwst;
public function __construct($id,$name,$beschreibung,$ek,$vk,$mwst){

$this->id=$id; $this->name=$name;
$this->beschreibung=$beschreibung;
$this->ek=$ek; $this->vk=$vk; $this->mwst=$mwst;
}
public function getId(){
return $this->id;
}
...
public function getMwSt(){
return $this->mwst;
}
}
?>
Listing 4.34: Die Klasse „Artikel“
Listing 4.33: Die Klasse „Rechnungsposition“ (Forts.)
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
4 – PHP objektorientiert
248
Abbildung 4.7: Objektdiagramm einer Rechnungsposition mit einem Artikel
Zunächst wird der Artikel erstellt und danach die Rechnungsposition. Diese erhält beim
Konstruktoraufruf die Referenz auf den Artikel. Interessant ist auch die Möglichkeit,
über die Rechnungsposition den Artikel zu ermitteln und dann eine Methode dieses
Artikels, in diesem Fall getBeschreibung(), aufzurufen. Dieser Aufruf kann über $pos01-
>getArtikel()->getBeschreibung() in einer Zeile erfolgen.
Somit lautet die Ausgabe des Testprogramms wie folgt:
Name: Butter
Beschreibung: gute Butter
Menge: 5
Einzelpreis: 0.70 EUR
Gesamtpreis: 3.75 EUR

4.2.3 Wechselseitige Bekanntschaften
Schwieriger zu realisieren ist die wechselseitige Assoziation zweier Klassen. Als Beispiel
wird die Beziehung zwischen Studenten und Praktika realisiert. Da ein Student eine spe-
zielle Person ist, kann die implementierte Personenklasse aus Listing 4.24 weiterverwen-
det werden.
<?php require_once("classloader.inc.php"); ?>
<html><body>
<?php
$a2=new Artikel(2,'Butter','gute Butter',0.50,0.70,7);
$pos01=new Rechnungsposition($a2,5,0);
echo 'Name: '.$pos01->getArtikel()->getName().'<br>';
echo 'Beschreibung: '.$pos01->getArtikel()->getBeschreibung().'<br>';
echo 'Menge: '.$pos01->getMenge().'<br>';
echo 'Einzelpreis: '.number_format($pos01->getEP(),2).' EUR<br>';
echo 'Gesamtpreis: '.number_format($pos01->getGesamtpreis(),2).
' EUR<br>';
?>
</body></html>
Listing 4.35: Test einer Rechnungsposition und eines Artikels
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Realisierung von Klassengeflechten
PHP – Endlich objektorientiert 249
Im Gegensatz zu einer Person besitzt ein Student zusätzlich eine Matrikelnummer und
ein Datum der Immatrikulation. Ein Student kann sich an bis zu 5 Praktika gleichzeitig
anmelden. Man kann einen Studenten fragen, an welchen Praktika er teilnimmt. Er gibt
daraufhin ein Datenfeld seiner Praktikumsobjekte zurück.
Nach einer Anmeldung soll der Student sein Praktikum kennen, er muss ja wissen, an
welchen Veranstaltungen er teilnimmt, und gleichzeitig muss auch das Praktikum seine
Studenten kennen, da ggf. eine Anwesenheitspflicht besteht.
Ein Praktikum hat einen Namen und eine Zeitdauer, in dem es stattfindet. Zu einem

Praktikum können sich bis zu 20 Studenten anmelden. Eine andere Sichtweise besteht
darin, dass sich ein Student an einem Praktikum anmeldet. Beide Klassen verfügen also
über eine Methode anmelden.
Abbildung 4.8: Wechselseitige Beziehung zwischen Praktika und Studenten
Profitipp
Sie erkennen hier, dass eine sinnvoll durchdachte abstrakte Klasse auch in verschie-
denem Kontext – in Listing 4.24 war der Kontext die Ableitung von Kunden und Mit-
arbeitern – weiterverwendet werden und damit langfristig Ressourcen der Imple-
mentierung einsparen kann.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
4 – PHP objektorientiert
250
Der Vorgang der Anmeldung ist also der Kern dieses Problems. Ein Student kann sich
bei einem Praktikum anmelden und umgekehrt. Im Anschluss an eine Anmeldung müs-
sen die Objekte beider Klassen eine Referenz auf das jeweils andere Objekt besitzen. Hier
besteht die Gefahr einer endlos laufenden Rekursion.
Das Aktivitätsdiagramm auf Muschelebene der Abbildung 4.9 zeigt die Anmeldung
eines Studenten s an einem Praktikum p mit der Methode s.anmelden(p). Der umgekehrte
Fall p.anmelden(s) verläuft analog. Die Pfeile des regulären Ablaufs sind etwas dicker dar-
gestellt. Dies ist nicht in der UML spezifiziert, erhöht jedoch die Übersichtlichkeit.
Abbildung 4.9: Aktivitätsdiagramm zur Anmeldung eines Studenten an einem Praktikum
Zunächst wird ein Praktikumsobjekt an die anmelden-Methode des Studenten übergeben.
Da PHP die Datentypen nicht im Vorfeld festlegt, muss man zuerst prüfen, ob es sich bei
der Eingabe um ein Praktikum handelt.
Im zweiten Schritt wird geprüft, ob der Student bereits an diesem Praktikum angemeldet
ist. Wenn dies der Fall ist, ist der Anmeldevorgang bereits erfolgreich beendet.
Da sich ein Student gleichzeitig für maximal 5 Praktika anmelden kann, wird bei der
dritten Prüfung ermittelt, ob die Obergrenze schon im Vorfeld erreicht ist. Ist dies nicht
Hinweis
Die Anzahl der Eigenschaften und der Methoden ist in diesen Beispielen natürlich

beschränkt, sodass Sie die Testprogramme noch nicht in der Realität einsetzen kön-
nen. Es geht vielmehr darum, dass Sie den Quellcode verstehen, der die Beziehungen
zwischen den Klassen realisiert und dass Sie diesen Code auch bei der Lösung ande-
rer Problemstellungen einsetzen können.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Realisierung von Klassengeflechten
PHP – Endlich objektorientiert 251
der Fall, hat der Student noch freie Kapazitäten und kann sich die Referenz auf das Prak-
tikum merken. Dann wird die Anzahl der belegten Praktika erhöht.
Bis zu diesem Zeitpunkt weiß das Praktikum unter Umständen noch nichts von der
Anmeldung. Daher versucht der Student nun, sich beim Praktikum anzumelden. Wenn
dies erfolgreich ist, wurde der gesamte Anmeldevorgang erfolgreich abgeschlossen.
Andernfalls ist die Anzahl der belegten Praktika wieder zu verringern, das Praktikum
wieder aus der Liste der besuchten Praktika zu entfernen und der Anmeldevorgang ist
fehlgeschlagen.
Es stellt sich die Frage, warum der Student sich zuerst die Praktikumsreferenz merkt und
dann bei einem Fehlschlag bei der Anmeldung am Praktikum die Referenz wieder
löscht. Dies ist notwendig, da bei der Anmeldung am Praktikum intern wieder die
eigene anmelden-Methode aufgerufen wird und die Gefahr der endlosen Rekursion
besteht. Bei dieser Lösung gibt die Anmeldung des Studenten beim zweiten Aufruf
jedoch auf Grund der zweiten Prüfung im Aktivitätsdiagramm TRUE zurück, noch
bevor die Rekursion beim Praktikum anmelden noch einmal aufgerufen wird.
Diese textuelle Beschreibung, die wiederum aus dem Aktivitätsdiagramm resultiert,
wird nun in Listing 4.36 in Quellcode gegossen.
<?php
class Student extends Person{
private $matrNr; private $immatrikuliertSeit;
private $praks=Array(); private $anzPraks=0; const MAX_PRAKS=5;
public function __construct($matrNr,$name,$vorname,$strasse,$plz,$ort,
$immatrikuliertSeit){

parent::__construct($name,$vorname,$strasse,$plz,$ort);
$this->matrNr=$matrNr;
$this->immatrikuliertSeit=$immatrikuliertSeit;
}
public function GetMatrNr(){
return $this->matrNr;
}
public function getImmatrikuliertSeit(){
return $this->immatrikuliertSeit;
}
public function getPraktika(){
return $this->praks;
}
public function anmelden($prak){
Listing 4.36: Die Klasse „Student“
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.

×