Profil | Mitglieder | Registrieren | Start | Suche


PHP-Support.de » Programmierung » PHP & MySQL » Codeschnipsel » Design Patterns in PHP5    » Hallo Gast [Login | Registrieren]

Neues Thema | Antworten   

Autor Beitrag
B.C.
Mitglied
Sehr guter User


Dabei seit: 04.02.2009
Herkunft: Niedersachsen
Posts: 797
     Design Patterns in PHP5 Zitat | Bearbeiten

Design Patterns bieten elegante Lösung für häufig aufkehrende Probleme in der objektorientierten Programmierung.

Hi,

Ich möchte hier mal einige Design Patterns, auf Deutsch Entwurfsmuster, vorstellen. Dieser Thread
soll auch als Sammelthread für solche Entwurfsmuster sein. Na ja, ich lege mal vor:

Singleton
Oft besteht das Problem, dass man zB bei einer Datenbankklasse ein Konstrukt hat, dass die
Verbindung zur Datenbank herstellt. Aber nun möchte man nicht, dass die Verbindung 2 Mal
ausgeführt wird, sprich, es darf nur einmal ein Objekt dieser Klasse vorhanden sein und es dürfen
auch nicht mehr Objekte erstellt werden.

Hier mal ein Codeschnipsel für Singleton:
 PHP 
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
<?php
class Singleton
   
{
      
//Unser Objekt der Klasse Singleton
      
private static $objekt null;

      
//Konstruktor
      
private function __construct ()
         {
            
//Könnte auch ne Datenbankverbindung sein
            
printf('Konstruktor der Klasse %s wurde aufgerufen!',
            
get_class($this) );
         }

      public static function 
getInstance ()
         {
            
//Falls noch nich getan, Referenz
            //der Klasse auf das Objekt übertragen
            
if(is_null(self::$objekt))
               
self::$objekt = new Singleton;

            
//Objekt zurückgeben
            
return self::$objekt;
         }
   } 
//Ende: Singleton

//Anwendung:

//Gibt die Instanz der Klasse zurück
//und führt den Konstruktor aus
$Objekt Singleton::getInstance();

//Noch eine Instanz
//Diesmal wird der Konstruktor nicht ausgeführt,
//man erhält genau das gleiche Objekt wie $Objekt
$Objekt2 Singleton::getInstance();
?>



Fabrik
Eine Fabrik baut Objekte zur Laufzeit zusammen. Das ist ganz praktisch, wenn man zur Laufzeit
des Skriptes noch nicht genau weiß, ob überhaupt und welches Objekt benötigt wird. Welche Klasse
benötigt wird, kann zB erst über Get-Parameter deutlich werden, daher wäre es sinnlos, alle 100
Klassen zu includen, obwohl nur eine benötigt wird.

Codeschnipsel für eine Factory
 PHP 
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
<?php
class Factory
   
{
      
/**
      * Konstante, Pfad zu den Klassen
      */
      
const DIR '/Pfad/zu/den/Klassen/';

      
/**
      * Baut das Objekt zusammen, mit Fehlerbehandlung
      * und Paketmöglichkeiten
      *
      * @param  string  $class - Name der Klasse
      * @param  mixed   $param - Parameter der Klasse
      * @return  objekt - Instanz der Klasse
      */
      
public static function getClass ($className$param null)
         {
            
//Ist der Klassenname gültig?
            
if(!is_string($className))
               exit (
'Kein g&uuml;ltiger Klassenname: ' $className);

            
//Existiert die Klasse schon?
            
if(!class_exists($className))
               exit(
'Die Klasse existiert schon: ' $className);

            
//Existiert die Datei?
            
$file self::DIR str_replace('::''/'$className) . '.class.php';
            if(!
file_exists($file))
               exit(
'Die Datei existiert nicht: ' $file);

            require_once (
$file);

            try
               {
                  
//Name vom Paket trennen
                  
$tmp explode('::'$className);
                  
$class array_pop($tmp);

                  
//Objekt bauen
                  
$objekt = new $class($param);
               }
            catch(
Exception $e)
               {
                  throw new 
Exception ('Fehler beim Konstruiren des Objektes<br />
                                        Failes to construct the object: \'' 
$className '\'');
               }
         }
   }

//Anwendung:

//Bindet Klasse: /Pfad/zu/den/Klassen/Datenbak/MySQL.class.php ein
//Und erstelt Objekt der Klasse 'MySQL'
$objekt =& Factory::getClass('Datenbank::MySQL');

//Man könnte in der Fabrik noch ein Singleton einbaun,
//also ein Array, das alle erstellten Objekte speichert.
//Und wenn eins erneut erstellt wird, das passende Objelt
//aus dem Array zurückgeben...
?>


Es gibt noch viele weitere Design Patterns, aber jetzt hab ich grad keine Lust mehr
Hinzu kommt noch:

Observer Pattern
Fassade Pattern

Es gibt noch viele viele mehr, also schön sammeln
Freue mich über jedes hier reingestelltes Design Pattern

Gruß,
Basti




Post wurde schon 6x editiert, das letzte mal am 22.08.2010 um 15:30 von Andavos
06.10.2009, 13:53 Profil | PM | E-Mail  
B.C.
Mitglied
Sehr guter User


Dabei seit: 04.02.2009
Herkunft: Niedersachsen
Posts: 797
     Observer Pattern Zitat | Bearbeiten

Hi,

so jetzt kommt das Oberver (Beobachter) Pattern. Dabei wird eine Klasse mein Ablauf "beobachtet"
und wenn sich die zu beobachtete Klasse verändern, werden die Beobachter informiert und
reagieren darauf meist mit einer Ausgabe. Das kann
man gut zur Aufgabentrennung der Klassen benutzen, zB im MVC (Model-View-Controller) Konzept anwenden. Dabei ist der Observer für die
Präsentation (view) verantwortlich und die beobachtete Klasse (model) für die Bearbeitung der Daten.

Ok, ich hab mir mal was ganz anschaulisches programmiert im Bezug auf ein Countdown.

 PHP 
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
<?php

//Interface zur Kontrolle
interface isObserver {
}

interface 
Observable {
}


/**
* Die Klasse, die beobachtet wird
* Um sie eindeutig als zu beobachtene Klasse
* zu definieren, bekommt die das passende Interface
*/
class Countdown implements Observable
   
{
      public 
$counts     10//Zählstand (Status)
      
private $observers = array(); //Alle Oberserver dieser Klasse

      //Fügt dieser Klasse einen neuen Beobachter zu
      //Aber nur, wenn das Objekt dem Interface "isObserver" angehört
      //attach (deut. = anhängen)
      
public function attach (isObserver $observer)
         {
            
$this->observers[] = $observer;
         }

      
//dettach (=trennen) schließt einen Observer aus
      
public function dettach (isObserver $observer)
         {
            if(
in_array($observer$this->observers))

               unset(
$this->observers[$observer]);
         }

      
//notify (=benachrichtigen) sagt allen
      //Observern bescheid
      
private function notify ()
         {
            foreach(
$this->observers as $observer)

               
$observer->update($this);
         }

      
//Zählt den Status runter
      
public function startCount ()
         {
            while(
$this->counts 0)
               {
                  
$this->counts--; //Um 1 runterzählen

                  /* Allen Observern sagen, dass wir
                     unseren Status geändert haben */
                  
$this->notify();
               }
         }
   }

//Unser erster Beobachter, Observer1
class Observer1 implements isObserver
   
{
      
//Ausgabe, welche Klasse sich geändert hat
      
public function update (Observable $subjekt)
         {
            
printf('Der Status der Klasse "%s" hat sich ge&auml;ndert!<br />',
            
get_class($subjekt) );
         }
   }

//Beobachter vom Typ 2
class Observer2 implements isObserver
   
{
      
//Ausgabe, den aktuellen Status der Klasse ausgeben (Zählstand)
      
public function update (Observable $subjekt)
         {
            echo 
'Der Z&auml;hlstand betr&auml;gt nun: ' $subjekt->counts '<br /><br />';
         }
   }

//Objekt der zu beobachteten Klasse erzeugen
$wird_beobachtet = new Countdown;

//Dem Countdown einen Beobachter hinzufügen
$beobachter_1 = new Observer1;
$wird_beobachtet->attach($beobachter_1);

//Und den 2ten Beobachter hinzufügen
$beobachter_2 = new Observer2;
$wird_beobachtet->attach($beobachter_2);

//Das Zählen starten
$wird_beobachtet->startCount();
?>


Die Ausgabe vom diese Code:
 PHP 
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
Der Status der Klasse "Countdown" hat sich geändert!
Der Zählstand beträgt nun: 9

Der Status der Klasse "Countdown" hat sich geändert!
Der Zählstand beträgt nun: 8

Der Status der Klasse "Countdown" hat sich geändert!
Der Zählstand beträgt nun: 7
          .
          .
          .


Wenn iwas unverständlich oder unklar ist, immer nachfragen

Weiterführende Links:
MVC (Model-View-Controller)

Gruß,
Basti




Post wurde schon 2x editiert, das letzte mal am 07.10.2009 um 16:02 von B.C.
07.10.2009, 14:53 Profil | PM | E-Mail  
B.C.
Mitglied
Sehr guter User


Dabei seit: 04.02.2009
Herkunft: Niedersachsen
Posts: 797
     Fassade Pattern Zitat | Bearbeiten

Hi,

nun wieder das nächste Entwurfsmuster, das Fassade (Facade) Pattern. Das lässt sich gut
anhand eines Beispiels mit einem Auto erklären. Du bist besitzer eines Autos, das diese Eigenschaften
hat:

Farbe
Räder
Modell

und das kannst du damit machen:

angucken
losfahren

Demnach sieht die Autoklasse so aus:

 PHP 
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
<?php
class Auto
   
{
      
//Eigenschaften des Autos
      
private $farbe 'schwarz';
      private 
$raeder 5;
      private 
$modell 'BMW';

      
//Eine Eigenschaft ausgeben
      
public function angucken ($eigenschaft)
         {
            switch (
$eigenschaft)
               {
                  case 
'farbe': return $this->farbe;
                  case 
'raeder': return $this->raeder;
                  case 
'modell': return $this->modell;
                  default: return 
'Das Auto hat kein ' $eigenschaft;
               }
         }

      
//Mit dem Auto wegfahren :)
      
public function losfahren ()
         {
            echo 
'Auto ist gestartet.';
         }
   }
?>


Jetzt will man das Auto aber ausstellen, sodass es jeder angucken kann. Natürlich willst du sein
Auto behalten, also darf keiner damit losfahren können.
Aber das soll ermöglicht werden, ohne irgendetwas an der Klasse "Auto" zu verändern. Dabei hilft dieses
Pattern! Wir lassen das Auto durch ein Vertreter Objekt vertreten, diese hat dann den beschränkten
Zugriff auf das Auto.

 PHP 
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
<?php
require_once ('AutoKlasse_überDieserHier.php');

class 
AutoAusstellungVertreter
   
{
      
//Die Instanz vom Auto
      
private $autoObjekt;

      
//Der Vertreter Klasse das Objekt zuweisen
      
public function __construct (Auto $auto)
         {
            
$this->autoObjekt $auto;
         }

      
//Die Methode angucken implementieren
      
public function angucken ($eigenschaft)
         {
            return 
$this->autoObjekt->angucken($eigenschaft);
         }
   }

//Anwendung:

//Objekt erstellen und Objekt vom Auto übergeben
$Ausstellung = new AutoAusstellungVertreter(new Auto);

//Beispiel
echo $Ausstellung->angucken('farbe');
?>


Jetzt kann man das Auto nur noch angucken und nicht mehr damit wegfahren Sowas ist ganz
nützlich, wenn man nur beschränkten Zugriff auf eine Klasse erlauben will. Wie man dieses Pattern
noch erweitern kann, zeigt mein nächstes Pattern Decorator. Momentan haben wir die Auto-Klasse
delegriert, also sozusagen verkleinert. Mit dem Decorator können wir die Klasse noch um Funktionen erweitern.
Dazu später mehr

Gruß,
Basti




Post wurde schon 1x editiert, das letzte mal am 12.10.2009 um 00:54 von B.C.
09.10.2009, 14:17 Profil | PM | E-Mail  
electro_dave
Mitglied
Guter User


Dabei seit: 27.08.2009
Herkunft: Schweiz
Posts: 487
      Zitat | Bearbeiten

und was bringen diese patterns??


jeder macht was er will, doch jeder steht dazu was er macht...
19.10.2009, 11:30 Profil | PM | E-Mail  
spooooongq
Mitglied
Sehr guter User


Dabei seit: 27.02.2009
Herkunft:
Posts: 803
      Zitat | Bearbeiten

lesen muss man können: 2 zeile ganz oben...


Signaturen sind doof
19.10.2009, 12:08 Profil | PM | E-Mail  
yoshi-
Mitglied
Guter User


Dabei seit: 29.07.2009
Herkunft: keine Angabe
Posts: 374
      Zitat | Bearbeiten

Zitat:
Orginal von spooooongq
lesen muss man können: 2 zeile ganz oben...

nö sind richtig schlecht erklärt, jmd der nicht weißt wofürm man es bruacht versteht nichts


19.10.2009, 12:42 Profil | PM | E-Mail  
stex
Mitglied
Sehr guter User


Dabei seit: 14.04.2009
Herkunft: Hannover
Posts: 650
      Zitat | Bearbeiten

http://tinyurl.com/yf3zera


19.10.2009, 12:49 Profil | PM | E-Mail  
B.C.
Mitglied
Sehr guter User


Dabei seit: 04.02.2009
Herkunft: Niedersachsen
Posts: 797
      Zitat | Bearbeiten

Zitat:
Orginal von electro_dave
und was bringen diese patterns??


Hab ich doch oben beschrieben:

Singleton
Wenn man von einer Klasse nur ein Objekt haben will und nicht mehr. Dies verhindert auch, dass
dadurch der Konstruktor merhmals ausgeführt wird.

Fabrik
Wenn du zur Laufzeit des Skriptes noch nicht weiß, welche Klasse benötigt wird, kann man
dadurch die Klassen ganz gut hinzufügen. Einfach die Factory-Methode aufrufen und schon ist die
Datei includier und wird erstellt. Ist eigentlich ganz praktisch ...

Observer
Wenn du den Status einer Klasse beobachten und auf Statusänderungen reagieren willst. Ein
Beispiel zeit sich deutlich im MVC Konzept (Einfach bei WIkipedia nachlesen )

Fassade
Hab ich doch mit dem Auto gut erklärt oder nicht


Zitat:
Original von yoshi-
nö sind richtig schlecht erklärt, jmd der nicht weißt wofürm man es bruacht versteht nichts

Wenn man nicht in OOP programmiert (wie electro_dace vermutlich) sind diese Patterns
natürlich schwerer zu verstehen, wenn man die ganze OOP-Logik noch nicht kennt.
Was meint du aber micht richtig schlecht erklärt? Ohne Begründung ist das eine richtig schlechte Kritik

Gruß,
Basti




Post wurde schon 1x editiert, das letzte mal am 19.10.2009 um 18:42 von B.C.
19.10.2009, 18:41 Profil | PM | E-Mail  
yoshi-
Mitglied
Guter User


Dabei seit: 29.07.2009
Herkunft: keine Angabe
Posts: 374
      Zitat | Bearbeiten

Bei einen Singleton ist der Vorteil weniger das man nur eine Instanz haben kann sondern das sie global verfügbar.

Und du konntest z.b. noch sagen wo der Vorteil einer Factory Klasse gegenüber der interzeptor funktion __autoload ist

Außerdem fällt vorallem bei den Beispiel mit den Auto auf, das du nicht erklärst wo man dieses Pattern benutzen sollte.




Post wurde schon 1x editiert, das letzte mal am 19.10.2009 um 18:56 von yoshi-
19.10.2009, 18:53 Profil | PM | E-Mail  
Teralios
Moderator
Perfekter User


Dabei seit: 18.09.2005
Herkunft: Berlin
Posts: 2542
      Zitat | Bearbeiten

Und dann kommen wir bei jedem Pattern mit Vor- und Nachteilen, und so weiter.

Singelton => Lohnt sich nur, wenn eine Klasse einzeln vorhanden sein soll, weil man hiervon nicht mehre Objekte braucht. Typische Beispiele wäre eine Template Klasse oder Datenbankklasse in einem bestimmten Umfeld. (Man kann beides aber auch mehrfach gebrauchen, je nach Programm)

Das hier vorgeführte SingelTon Modell ist noch eine Abschwächung, da hier immer noch geklont werden kann. Man muss also __clone noch verhindern.

Nachteile können entstehen, wenn man, wie oben erwähnt, doch mal von etwas eine neue Instanz braucht. Oftmals macht so was in einer sehr abgeschwächten Form Sinn oder bei einer Grundklasse, die z.B. verschiedene Ansätze für das selbe Problem bereit stellt.
 PHP 
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
<?php
class MailSender {
    protected function 
__construct() { }
    public static function 
getMailSender($type) {
        
$className $type.'MailSender';
        
$file 'dir/'.$className.'.class.php';
        if (
file_exists($file)) {
            require_once(
$file);
            if (
class_exists($className) {
                return new 
$className();
            }
        }
        return 
null
    
}
}

class 
SmtpMailSender extends MailSender {
}

Es ist, wie gesagt eine abgeschwächte Form mit einer Factory.

Damit sind wir bei den Factories. Auch diese machen nur Sinn, wenn man diese in einem Kontext stellt, wie hier beim MailSender vorgeführt. Eine allgemeine Factory macht selten Sinn, da viele Klassen meist auch Parameter haben, oder bei einer ordentlichen Unterteilung macht es mit diesen keinen Sinn, da zu viele Fälle abgefangen werden müssen. Selbes gilt für Autoload.

Factory macht also nur Sinn in einem Zusammenhang von Klassen, die einen Kontext zusammen bilden. Ich benutze dieses also immer genau dann, wenn ich eine abstrakte Klasse habe, die für eine Aufgabe gedacht ist, diese aber auf verschiedene Arten implementiert werden kann. Hier kann ich die Factory auch immer direkt soweit anpassen, wie es angepasst werden muss.

Autoload nutze ich immer dann, wenn ich eine Klasse habe, die im Konsturktor Parameter haben und vorallem wenn es immer wiederkehrende Klassen sind, wie Exceptions oder auch kleinere Hilfsklassen.

Observer-Klassen machen in wenigen Fällen wirklich Sinn, vorallem in PHP und dem dortigen MVC-Schema. Je nach Schema, was man implementiert sind. WCF kann man sich gerne dafür anschauen. Observer machen Sinn in einem Dienst, in Java nutze ich sowas schon öfters, die einem anderen Thread meldet, wenn sich was im aktuellen Thread ändert. Bei Skriptsprachen ist so was zwar schön einzubauen, aber Sinnvoll ist es weniger. Vorallem weil der Controller meist den Aufruf abarbeitet und dann entsprechend mit den Modell-Klassen umgeht. Fazit für Observer in PHP => Absolut Schwachsinnig, da es eine Skriptsprache ist und der Controller meist diese Aufgabe übernimmt. Das MVC ist hier also eher so zu verstehen

View <-> Controller <-> Model
Bei Skriptsprachen ist das aber auch einfacher anzuwenden, also das übliche MVC-Modell.


Zugriffsbeschränkungen mit Fassaden macht meistens Sinn, wenn man eine Pluginschnittstelle realisieren will, wo andere Klassen auf Zustände reagieren des Objektes, aber das Objekt nicht selbst ändern dürfen. Man übergibt also ein Objekt einem weitern Objekt und reicht dieses dann an die entsprechende Schnittstelle.




Post wurde schon 1x editiert, das letzte mal am 21.10.2009 um 10:14 von Teralios
21.10.2009, 10:12 Profil | PM | E-Mail  
Seiten (1):  1 
PHP-Support.de » Programmierung » PHP & MySQL » Codeschnipsel » Design Patterns in PHP5   

Neues Thema | Antworten   


Powered by Command Board 1.0 - Beta 2.0 © 2004-08 PHP-Einfach | Impressum | Datenschutz