{"id":426,"date":"2010-12-01T00:04:20","date_gmt":"2010-11-30T23:04:20","guid":{"rendered":"https:\/\/d-mueller.de\/blog\/?p=426"},"modified":"2010-12-01T00:04:20","modified_gmt":"2010-11-30T23:04:20","slug":"5-php-patterns-im-schnelldurchlauf-factory-iterator-observer-singleton-strategy","status":"publish","type":"post","link":"https:\/\/d-mueller.de\/blog\/5-php-patterns-im-schnelldurchlauf-factory-iterator-observer-singleton-strategy\/","title":{"rendered":"5 PHP Patterns im Schnelldurchlauf: Factory, Iterator, Observer, Singleton, Strategy"},"content":{"rendered":"<p>Dieser Post versteht sich ein bisschen als &#8222;Reminder&#8220;. Bei den folgenden 5 Patterns habe ich in den Codebeispielen besonderen Wert auf Einfachheit gelegt, sodass man ohne gro\u00dfe Erkl\u00e4rung gleich sieht, worum es geht. Ich finde es wichtig, sich nach einiger Zeit immer mal wieder die Patterns vor Augen zu halten.<\/p>\n<h2>Factory<\/h2>\n<p>Eine &#8222;Fabrik&#8220; erzeugt je nach Anwendungskontext verschiedene Klassen und gibt diese zur\u00fcck.<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\ninterface IPermission\r\n{\r\n\tpublic function deleteFilePermission();\r\n}\r\n\r\nclass AdminPermission implements IPermission\r\n{\r\n\tpublic function deleteFilePermission()\r\n\t{\r\n\t\treturn true;\r\n\t}\r\n}\r\n\r\nclass UserPermission implements IPermission\r\n{\r\n\tpublic function deleteFilePermission()\r\n\t{\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\n\/\/-----------------------------------------------\r\n\r\nclass UserFactory\r\n{\r\n\tpublic static function build($type)\r\n\t{\r\n\t\tswitch ($type)\r\n\t\t{\r\n\t\t\tcase &#039;admin&#039;: \r\n\t\t\t\treturn new AdminPermission();\r\n\t\t\t\tbreak;\r\n\t\t\tcase &#039;user&#039;: \r\n\t\t\t\treturn new UserPermission();\r\n\t\t\t\tbreak;\r\n\t\t\tdefault: \r\n\t\t\t\tthrow new Exception(&quot;No valid type&quot;);\r\n\t\t}\t\t\t\r\n\t}\r\n}\r\n\r\n\/\/-----------------------------------------------\r\n\r\n\/\/admin is allowed to delete files\r\n$admin=UserFactory::build(&quot;admin&quot;);\r\nvar_dump($admin-&gt;deleteFilePermission()); \/\/bool(true)\r\n\r\n\/\/user is not allowed to delete files\r\n$user=UserFactory::build(&quot;user&quot;);\r\nvar_dump($user-&gt;deleteFilePermission()); \/\/bool(false)\t\r\n<\/pre>\n<h2>Iterator<\/h2>\n<p>Das iterieren mit foreach ist durch das Iterator-Pattern auch \u00fcber eine Klasse m\u00f6glich &#8211; so als ob sie ein Array w\u00e4re. Sinnvoll, wenn ich klassenintern komplexe Strukturen abgebildet habe, die ich nach au\u00dfen simpel darstellen m\u00f6chte. Allerdings ist mein Beispiel bewusst einfach gehalten &#8211; eigentlich eine Vergewaltigung des iterator-Patterns, bei dem ein einfaches Array die bessere Wahl gewesen w\u00e4re. Aber der Zusammenhang sollte klar werden.<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\nclass LottoNumbers implements Iterator \r\n{\r\n\tprivate $_lottoNumbers;\r\n\tprivate $_currentPos = 0;\r\n \r\n\tpublic function __construct(array $lottoNumbers) \r\n\t{\r\n\t\t$this-&gt;_lottoNumbers = $lottoNumbers;\r\n\t}\r\n \r\n\tpublic function current() \r\n\t{\r\n\t\treturn $this-&gt;_lottoNumbers[$this-&gt;_currentPos];\r\n\t}\r\n \r\n\tpublic function key() \r\n\t{\r\n\t\treturn $this-&gt;_currentPos;\r\n\t}\r\n \r\n\tpublic function next() \r\n\t{\r\n\t\t++$this-&gt;_currentPos;\r\n\t}\r\n \r\n\tpublic function rewind() \r\n\t{\r\n\t\t$this-&gt;_currentPos=0;\r\n\t}\r\n \r\n\tpublic function valid() \r\n\t{\r\n\t\treturn isset($this-&gt;_lottoNumbers[$this-&gt;_currentPos]);\r\n\t}\r\n}\r\n\r\n$lotto = new LottoNumbers(array(12,41,14,34,3,23));\r\n\r\nforeach ($lotto as $nr =&gt; $lottoNumber) \r\n{\r\n\techo &quot;Lottonr.&quot;.$nr.&quot; = &quot;.$lottoNumber.&quot;&lt;br \/&gt;&quot;;\r\n}\r\n<\/pre>\n<p>Dabei ist das iterator-Interface selbst &#8222;php-intern&#8220; wie folgt definiert:<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\ninterface Iterator\r\n{\r\n\tabstract public mixed current ( void )\r\n\tabstract public scalar key ( void )\r\n\tabstract public void next ( void )\r\n\tabstract public void rewind ( void )\r\n\tabstract public boolean valid ( void )\r\n}\r\n<\/pre>\n<h2>Observer<\/h2>\n<p>Eines der klassischsten Patterns \u00fcberhaupt. Wird verwendet, um das Polling obsolet zu machen. Wenn es mehrere Beobachter gibt, die sich f\u00fcr den Status eines Subjekts interessieren ist es doch viel intelligenter, dass das Subjekt die Beobachter selbst benachrichtigt wenn sich etwas tut. Im Polling-Verfahren w\u00fcrden die Beobachter st\u00e4ndig anfragen m\u00fcssen, ob es denn was neues gibt. Das Observer-Verfahren spart Rechenzeit und macht den Code sauberer.<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\ninterface Subject\r\n{\r\n\tpublic function addObserver(Observer $Observer);\r\n\tpublic function removeObserver(Observer $Observer);\r\n\tpublic function notify();\r\n}\r\n\r\nclass Train implements Subject\r\n{\r\n\tprotected $_minutesToArrival;\r\n\tprotected $_observers = array();\r\n \r\n\tpublic function __construct($mins)\r\n\t{\r\n\t\t$this-&gt;setMinutesToArrival($mins);\r\n\t}\r\n \r\n\tpublic function addObserver(Observer $observer)\r\n\t{\r\n\t\t$this-&gt;_observers[] = $observer;\r\n\t}\r\n \r\n\tpublic function removeObserver(Observer $observer)\r\n\t{\r\n\t\tfor ($i = 0; $i &lt; count($this-&gt;_observers); $i++)\r\n\t\t{\r\n\t\t\tif ($this-&gt;_observers[$i] === $observer)\r\n\t\t\t{\r\n\t\t\t\tunset($this-&gt;_observers[$i]);\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n \r\n\tpublic function notify()\r\n\t{\r\n\t\tforeach($this-&gt;_observers as $o)\r\n\t\t\t$o-&gt;update($this);\r\n\t}\r\n \r\n\tpublic function setMinutesToArrival($mins)\r\n\t{\r\n\t\t$this-&gt;_minutesToArrival = $mins;\r\n\t\t$this-&gt;notify();\r\n\t}\r\n \r\n\tpublic function getMinutesToArrival()\r\n\t{\r\n\t\treturn $this-&gt;_minutesToArrival;\r\n\t}\r\n}\r\n\r\n\/\/----------------------------------------------\r\n\r\ninterface Observer\r\n{\r\n\tpublic function update(Subject $Subject);\r\n}\r\n\r\nclass PassengerJohn implements Observer\r\n{\r\n\tpublic function update(Subject $train)\r\n\t{\r\n\t\techo &quot;John is glad that he arrives in &quot;.$train-&gt;getMinutesToArrival().&quot;mins&lt;br \/&gt;&quot;;\r\n\t}\r\n}\r\n\r\nclass PassengerMary implements Observer\r\n{\r\n\tpublic function update(Subject $train)\r\n\t{\r\n\t\techo &quot;Mary can sleep &quot;.$train-&gt;getMinutesToArrival().&quot;mins till she arrives&lt;br \/&gt;&quot;;\r\n\t}\r\n}\r\n\r\n\r\n\/\/----------------------------------------------\r\n\r\n$train = new Train(60);\r\n$john = new PassengerJohn();\r\n$train-&gt;addObserver($john);\r\n$mary = new PassengerMary();\r\n$train-&gt;addObserver($mary);\r\n$train-&gt;setMinutesToArrival(55);\r\n\/\/John is glad that he arrives in 55mins\r\n\/\/Mary can sleep 55mins till she arrives\r\n$train-&gt;setMinutesToArrival(45);\r\n\/\/John is glad that he arrives in 45mins\r\n\/\/Mary can sleep 45mins till she arrives\r\n$train-&gt;removeObserver($mary);\r\n$train-&gt;setMinutesToArrival(35);\r\n\/\/John is glad that he arrives in 35mins\r\n<\/pre>\n<h2>Singleton<\/h2>\n<p>Der Klassiker f\u00fcr Logger- oder Datenbank-Klassen, von denen es naturgem\u00e4\u00df sinnvollerweise nur eine Instanz geben sollte. Allerdings sollte man sich in Verbindung dazu auch <a href=\"http:\/\/blogs.msdn.com\/b\/scottdensmore\/archive\/2004\/05\/25\/140827.aspx\">die Kritik<\/a> am Singleton-Pattern durchlesen.<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\nclass MySingletonClass\r\n{\r\n    private static $_instance = null;\r\n\t\r\n    public static function getInstance() \r\n    {\r\n        if (self::$_instance === null)\r\n            self::$_instance = new self();\r\n \r\n        return self::$_instance;\r\n    }\r\n \r\n    final private function __construct() { }\r\n    final private function __clone() { }\r\n\t\r\n\tprivate $_val;\r\n\t\r\n\tpublic function getValue()\r\n\t{\r\n\t\treturn $this-&gt;_val;\r\n\t}\r\n\t\r\n\tpublic function setValue($val)\r\n\t{\r\n\t\t$this-&gt;_val = $val;\r\n\t}\r\n}\r\n \r\n$instance = MySingletonClass::getInstance();\r\n$instance-&gt;setValue(1337);\r\nprint $instance-&gt;getValue().&quot;&lt;br \/&gt;&quot;; \/\/1337\r\n\r\n$instance2 = MySingletonClass::getInstance(); \/\/same instance \r\nprint $instance2-&gt;getValue().&quot;&lt;br \/&gt;&quot;; \/\/1337\r\n<\/pre>\n<h2>Strategy<\/h2>\n<p>Sehr elegante L\u00f6sung, wenn es f\u00fcr einen Anwendungsfall mehrere Strategien geben kann. Die <i>Payment<\/i>-Klasse muss es garnicht interessieren, was es f\u00fcr Bezahlverfahren gibt. Sie kann sich darauf verlassen, dass sie eine Instanz einer Strategie \u00fcbergeben bekommt, die genau diesen Task erf\u00fcllt. Sinnvoll, um Klassen hoch erweiterbar zu halten und keine Lust auf endlose if \/ else Konstrukte hat.<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\ninterface IStrategy \r\n{\r\n    public function execute();\r\n}\r\n \r\nclass PayCreditCard implements IStrategy \r\n{\r\n    public function execute() \r\n\t{\r\n        echo &quot;Paying via Credit Card&lt;br \/&gt;&quot;;\r\n    }\r\n}\r\n \r\nclass PayCash implements IStrategy \r\n{\r\n    public function execute() \r\n\t{\r\n        echo &quot;Paying in cash&lt;br \/&gt;&quot;;\r\n    }\r\n}\r\n\r\n\/\/----------------------------------------------\r\n \r\nclass Payment \r\n{\r\n    private $_strategy;\r\n \r\n    public function __construct(IStrategy $strategy) \r\n\t{\r\n        $this-&gt;_strategy = $strategy;\r\n    }\r\n \r\n    public function execute() \r\n\t{\r\n        $this-&gt;_strategy-&gt;execute();\r\n    }\r\n}\r\n\r\n\/\/----------------------------------------------\r\n\r\n$payment1 = new Payment(new PayCash());\r\n$payment1-&gt;execute(); \/\/Paying in cash\r\n\r\n$payment2 = new Payment(new PayCreditCard());\r\n$payment2-&gt;execute(); \/\/Paying via Credit Card\r\n<\/pre>\n<p>Abschlie\u00dfend sei noch bemerkt, dass es hier und da ein paar Feinheiten bei den Patterns je nach Autor gibt. Der Grundgedanke bleibt aber der gleiche.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dieser Post versteht sich ein bisschen als &#8222;Reminder&#8220;. Bei den folgenden 5 Patterns habe ich in den Codebeispielen besonderen Wert auf Einfachheit gelegt, sodass man ohne gro\u00dfe Erkl\u00e4rung gleich sieht, worum es geht. Ich finde es wichtig, sich nach einiger &hellip; <a href=\"https:\/\/d-mueller.de\/blog\/5-php-patterns-im-schnelldurchlauf-factory-iterator-observer-singleton-strategy\/\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,5],"tags":[],"class_list":["post-426","post","type-post","status-publish","format-standard","hentry","category-php","category-software-engineering"],"_links":{"self":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/426","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/comments?post=426"}],"version-history":[{"count":0,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/426\/revisions"}],"wp:attachment":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/media?parent=426"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/categories?post=426"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/tags?post=426"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}