Abstract Factory mit PHP


Battersea Power Station from Train, 29-04-06
Attribution-NonCommercial License by DG Jones

Inzwischen beschäftige ich mich fast nur noch mit PHP und aus Skripten wird langsam Programmieren. Ich möchte hier mit einem tatsächlich im RL vorkommendes Beispiel zeigen, dass Design Patterns nicht nur elegant und oo. sind sondern auch bei kleineren Skripts sehr nützlich sind.

Vor einigen Wochen habe ich mein unsägliches WordPress Plugin geschrieben. Dort werden unter anderem auch Urls mit verschiedenen Diensten verkürzt. Quick ’n Dirty habe ich eine Klasse angelegt und Methoden wie getShortUrlIsgd(), getShortUrlTinyUrl() erzeugt. Am Anfang gings noch relativ gut, bis ich Anfragen für andere Services bekam. Die wurden dann nach gleichem Schema in die Klasse gepastet. Die Auswahl des Urlshortener verläuft dann auch entsprechend unelegant über ein Switch Case Statement:

switch ($selected_shortener){
	case 'is.gd':
		$new_url=$this->getShortUrlIsgd();
		break;
	case 'bit.ly':
		$new_url=$this->getShortUrlBitly(	  get_option('schmie_tw_bitly_usr'),
					get_option('schmie_tw_bitly_api'));
		break;
	case 'i2h.de':
		$new_url=$this->getShortUrlI2h();
		break;
	case 'tinyurl.com':
		$new_url=$this->;getShortUrlTinyurl();
		break;
	}//switch

Mit einem Erzeugungsmuster wird die Geschichte wesentlich eleganter. Ich habe mich für die „Abstrakte Fabrik“ / Abstract Factory Kit entschieden. dabei wird eine abstrakte Klasse geschrieben, die zur Laufzeit die tatsächlich zu verwendende Klasse einbindet. Zur Übersichtlichkeit habe ich auf include und require Mechanismen in dem Beispiel verzichtet.

Betrachten wir zunächst die Factory Klasse:

abstract class ShortenerInterface{
	//some attributes
	protected  $login, $apikey,$serviceurl,$longurl;

	protected function __construct($login="", $apikey=""){
		$this->login = $login;
		$this->apikey = $apikey;
	}

	public static function factory($class,$login="", $apikey=""){
		return new $class($login=$login, $apikey=$apikey);

	}//factory

	protected function get_url($longurl) {
	/** ... **/
	}//get_url

       //diese Funktion will in jeder abgeleiteten Klasse implementiert werden
	public abstract function get_short_url($url);

}//class

Der Konstruktor ist relativ egal für das Designprinzip. Außer Attributzuweisungen macht er nicht viel. Wesentlich interessanter ist die Methode factory. Durch das Schlüsselwort static kann die Methode aufgerufen werden, ohne vorher das Objekt zu instanziieren (geht auch schlecht bei abstrakten Klassen).

Zurückgegeben wird eine Instanz der Gewünschten Klasse. Die beiden Argumente werden einfach durchgereicht. Die Abstrakte Methode get_url($longurl) muß in jeder abgeleiteten Klasse implementiert werden.

Ein Beispiel:

class CTinyurl extends ShortenerInterface{
	public function get_short_url($longurl){
		$this->serviceurl='http://tinyurl.com/api-create.php?url=';
		return $this->get_url($longurl);
	}//function
}//class

Der Implementierungsaufwand ist minimal wie man sieht. An eine Konkrete Instanz kommt man so:

$iface = ShortenerInterface::factory("CTinyurl");
$iface->get_short_url("http://schmiddi.co.cc");

oder so:

$services = array('CIsgd', 'CTinyurl', 'CI2h', 'CBitly');
foreach ($services as $service){
	$iface = ShortenerInterface::factory($service,   "", "");
	$url =  $iface->get_short_url("schmiddi.co.cc");
	echo "$url
";

Seehr schön. Auch wenn man funktional (wie in meinem Plugin-Fall) schreiben muß, sollte man immer mal kurz darüber Nachdenken etwas aus der Softwaretechnik Vorlesung zu implementieren. Über Verbesserungen und Vorschläge würde ich mich wie immer sehr freuen.

Wer den Code haben will: factory

P.S.:Wer das Kraftwerk auf dem Bild erkennt hat einen wirklich guten Musikgeschmack.
Advertisements
Dieser Beitrag wurde unter php abgelegt und mit , , , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s