1. Trang chủ
  2. » Công Nghệ Thông Tin

PHP – Endlich objektorientiert- P10

30 218 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề PHP – endlich objektorientiert
Trường học Standard University
Chuyên ngành Computer Science
Thể loại Thesis
Năm xuất bản 2023
Thành phố Berlin
Định dạng
Số trang 30
Dung lượng 561,27 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Als Beispiel wird die Beziehung einer Rechnungsposition zu einem Artikel verwendet.Das Klassendiagramm der Abbildung 4.6 gibt dabei die Eigenschaften beider Klassenvor.. Abbildung 4.6: B

Trang 1

Die zweite Klasse, die von der Person abgeleitet werden soll, ist die Klasse der ter Dabei wird in gleicher Weise wie bei der Kundenklasse vorgegangen Nur die füreinen Mitarbeiter typischen Eigenschaften werden auch in der Mitarbeiterklasse festge-halten.

Mitarbei-Sie erkennen auch, dass alle Eigenschaften, die Mitarbeiter und Kunden gemeinsamhaben, ausschließlich in der Personenklasse gespeichert und verwaltet werden Aufdiese Weise wird doppelter Quellcode verhindert und die Wartbarkeit der Anwendungverbessert

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

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;

return $this->id;

} }

?>

Listing 4.26: Die abgeleitete konkrete Klasse „Mitarbeiter“

Listing 4.25: Die abgeleitete konkrete Klasse „Kunde“ (Forts.)

Trang 2

klasse ausgelagert? In PHP ist dies durchaus eine Designalternative, da der Datentypeiner Eigenschaft nicht im Vorfeld festgelegt werden muss Es können jedoch auch hierProbleme 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 ten dann die Set-Methoden des Kunden und des Mitarbeiters mit den entsprechendenPrüfungen überschrieben werden Wie man Methoden überschreibt, wird im nächstenBeispiel erläutert

könn-In Listing 4.27 werden zunächst die drei erzeugten Klassen getestet Es werden einKunde und ein Mitarbeiter erzeugt Weil beide auch Personen sind, besitzen sie die

Methode getAnschrift(), die in beiden Fällen aufgerufen wird Abschließend wird 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.

test-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 Kapitelumgesetzt Dort wurden im objektorientierten Design die Klassen aus Abbildung 4.5ermittelt

<?php require_once("classloader.inc.php"); ?>

<html><body>

<?php $a=new Kunde(1,'Frank','Dopatka','Hauptstrasse 4',51580,'Reichshof');

Trang 3

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 Lautgeben 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 bietetdies 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“

Trang 4

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 nochweitere Initialisierungen vorgenommen werden, die auch für ein Katzenobjekt vonBedeutung 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.)

Trang 5

Von der Hundeklasse wird wiederum die Dogge als spezieller Hund abgeleitet Da derHund 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

Trang 6

Der Test der Tierklassen erfolgt in Listing 4.32 Dabei wird ein Datenfeld angelegt, dasmit 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 derDogge 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();

Trang 7

4.2.2 Aufbau von Bekanntschaften: Assoziationen

Die Vererbung ist eine statische Abhängigkeit von Klassen, die zur Entwicklungszeitfestgelegt wird Die Bekanntschaft von Objekten untereinander entsteht jedoch erst zurLaufzeit Nachdem ein Objekt ein anderes Objekt kennt, kann es Methoden auf dembekannten 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 Klassenvor 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 Mengeeingekauft werden soll Diese Abhängigkeit besteht bereits beim Erstellen der Rech-nungsposition Zusätzlich wird der Einzelpreis des Artikels und ggf ein Rabatt auf diejeweilige Rechnungsposition festgehalten

Abbildung 4.6: Beziehung zwischen einer Rechnungsposition und einem Artikel

Listing 4.33 zeigt die Implementierung einer Rechnungsposition Der Artikel ist dabeieine Eigenschaft der Rechnungsposition und wird als Referenz im Konstruktor überge-ben Der Einzelpreis der Rechnungsposition wird aus dem Verkaufspreis des Artikelsermittelt Außerdem werden dir typischen Get-Methoden implementiert Der Gesamt-preis ist keine eigene Eigenschaft, sondern wird aus den existierenden Eigenschaftenunter Berücksichtigung des optionalen Rabatts auf die Rechnungsposition sowie derMehrwertsteuer 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“

Trang 8

Die in Listing 4.34 implementierte Artikelklasse hat keine Besonderheiten, sie tiert lediglich die aus dem Klassendiagramm geforderten Eigenschaften und bietet Get-Methoden dazu an.

implemen-Abbildung 4.7 zeigt nun ein Objektdiagramm des kleinen Testprogramms, das in Listing4.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.)

Trang 9

Abbildung 4.7: Objektdiagramm einer Rechnungsposition mit einem Artikel

Zunächst wird der Artikel erstellt und danach die Rechnungsposition Diese erhält beimKonstruktoraufruf 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 Beispielwird 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)

Trang 10

Im Gegensatz zu einer Person besitzt ein Student zusätzlich eine Matrikelnummer undein Datum der Immatrikulation Ein Student kann sich an bis zu 5 Praktika gleichzeitiganmelden Man kann einen Studenten fragen, an welchen Praktika er teilnimmt Er gibtdaraufhin ein Datenfeld seiner Praktikumsobjekte zurück.

Nach einer Anmeldung soll der Student sein Praktikum kennen, er muss ja wissen, anwelchen Veranstaltungen er teilnimmt, und gleichzeitig muss auch das Praktikum seineStudenten kennen, da ggf eine Anwesenheitspflicht besteht

Ein Praktikum hat einen Namen und eine Zeitdauer, in dem es stattfindet Zu einemPraktikum können sich bis zu 20 Studenten anmelden Eine andere Sichtweise bestehtdarin, 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 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

Trang 11

verschie-Der Vorgang der Anmeldung ist also der Kern dieses Problems Ein Student kann sichbei 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 Hierbesteht 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 beider Eingabe um ein Praktikum handelt

Im zweiten Schritt wird geprüft, ob der Student bereits an diesem Praktikum angemeldetist 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 derdritten 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ürlichbeschrä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 Beziehungenzwischen den Klassen realisiert und dass Sie diesen Code auch bei der Lösung ande-rer Problemstellungen einsetzen können

Trang 12

der Fall, hat der Student noch freie Kapazitäten und kann sich die Referenz auf das tikum merken Dann wird die Anzahl der belegten Praktika erhöht.

Prak-Bis zu diesem Zeitpunkt weiß das Praktikum unter Umständen noch nichts von derAnmeldung Daher versucht der Student nun, sich beim Praktikum anzumelden Wenndies erfolgreich ist, wurde der gesamte Anmeldevorgang erfolgreich abgeschlossen.Andernfalls ist die Anzahl der belegten Praktika wieder zu verringern, das Praktikumwieder aus der Liste der besuchten Praktika zu entfernen und der Anmeldevorgang istfehlgeschlagen

Es stellt sich die Frage, warum der Student sich zuerst die Praktikumsreferenz merkt unddann bei einem Fehlschlag bei der Anmeldung am Praktikum die Referenz wiederlö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“

Trang 13

Die Eigenschaften Matrikelnummer und das Datum der Immatrikulation sind nicht dieeinzigen Eigenschaften, die ein Student mehr besitzt als eine gewöhnliche Person.Zusätzlich muss auch die Beziehung zu den belegten Praktika festgehalten werden.

Dazu wird ein Datenfeld $praks definiert, as die Referenzen auf die Praktikumsobjekte

enthalten soll Zusätzlich wird die Anzahl der Praktika gespeichert, an denen der dent aktuell teilnimmt sowie die maximal mögliche Anzahl der Praktika als Konstante.Der Konstruktor und die Get-Methoden enthalten keinen spannenden Quellcode

Stu-Die anmelden-Methode prüft mit instanceof zunächst den Datentyp des übergebenen

Ein-gabeparameters Ist es kein Praktikum, so ist die Anmeldung fehlgeschlagen Dann wird

die Liste der Praktika in einer foreach-Schleife durchgegangen, die der Student bereits

besucht Ist die übergebene Referenz dort bereits vorhanden, war der Student bereitsangemeldet und der Anmeldevorgang endet erfolgreich Dann wird geprüft, ob der Stu-dent bereits seine maximale Anzahl an Praktika gespeichert hat Wenn dies der Fall ist,darf er sich nicht mehr für ein weiteres Praktikum anmelden

Dann beginnt die eigentliche Anmeldung, bei der der Zähler der Teilnahmen erhöht unddie Referenz auf das Praktikum gespeichert wird Dann muss das Praktikum noch überdie Teilnahme dieses Studenten informiert werden Der Student ruft also seinerseits denAnmeldevorgang des Praktikums auf Dabei muss ein Studentenobjekt übergeben wer-

den, also das eigene Objekt Dies ist möglich durch die Übergabe der $this-Referenz, die

ja eine Referenz auf das Objekt selbst darstellt Wenn diese Anmeldung fehlschlägt, wirddie eigene Anmeldung rückgängig gemacht und der Vorgang ist fehlgeschlagen.Andernfalls ist die Anmeldung erfolgreich verlaufen

if (($prak instanceof Praktikum)==FALSE) return FALSE;

foreach (($this->praks) as $elem => $wert){

if ($wert==$prak) return TRUE; // bereits angemeldet }

if ($this->anzPraks==Student::MAX_PRAKS) return FALSE;

} }

?>

Listing 4.36: Die Klasse „Student“ (Forts.)

Trang 14

Im Anschluss daran wird in Listing 4.37 die Praktikumsklasse vorgestellt mit ihrenEigenschaften des Namens sowie des Zeitraums, in dem das Praktikum stattfindet DieImplementierung ist identisch zur Studentenklasse.

Hinweis

Vergleichen Sie das Aktivitätsdiagramm aus Abbildung 4.9 mit der

anmelden-Methode aus Listing 4.36 Erkennen Sie die Übereinstimmung?

<?php class Praktikum{

private $name; private $von; private $bis;

private $studs=Array(); private $anzStuds=0; const MAX_STUDS=20;

public function construct($name,$von,$bis){

$this->name=$name; $this->von=$von; $this->bis=$bis;

} public function GetName(){

return $this->name;

} public function getVon(){

return $this->von;

} public function getBis(){

return $this->bis;

} public function getStudenten(){

return $this->studs;

} public function anmelden($stud){

if (($stud instanceof Student)==FALSE) return FALSE;

foreach (($this->studs) as $elem => $wert){

if ($wert==$stud) return TRUE; // bereits angemeldet }

if ($this->anzStuds==Praktikum::MAX_STUDS) return FALSE;

// anmelden

$this->studs[$this->anzStuds]=$stud;

$this->anzStuds++;

// dem Studenten Bescheid sagen

Listing 4.37: Die Klasse „Praktikum“

Trang 15

Bei einer Vererbung, wie sie beispielsweise zwischen Person und Student existiert, ist die

Abhängigkeit des Studenten von der Personenklasse größer als bei der Beziehung derStudenten und Praktika, da die Unterklasse nicht ohne ihre Oberklasse ausgeführt wer-den kann Die Personenklasse benötigt die Studentenklasse jedoch nicht

Der Quellcode des Listings 4.38 testet die beiden Klassen Dabei werden zwei Studentenund drei Praktika angelegt Es wird sowohl die Anmeldemethode der Studentenklasseals auch die Anmeldemethode des Praktikums getestet So wird die korrekte Funktion inbeiden Fällen sichergestellt

} }

?>

<?php require_once("classloader.inc.php"); ?>

<html><body>

<?php $s1=new Student(3423433,'Dopatka','Frank','Hauptstrasse 4',51580, 'Reichshof','01.10.2002');

$s2=new Student(8977678,'Grube','Clair','Kanzlergasse 1',16334, 'Berlin','01.04.2001');

foreach ($data1 as $index => $wert){

Listing 4.38: Test der Klassen „Student“ und „Praktikum“

Listing 4.37: Die Klasse „Praktikum“ (Forts.)

Ngày đăng: 29/10/2013, 02:15