Artikel zur Objektorientierung gibt es schon genügend (Wikipedia). Ich möchte hier anhand eines Beispiels die Unterschiede zur prozeduralen Programmierung verdeutlichen.
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 |
require 'globalconfig.php'; function paypalTransaction($amount, $buyerEmail, $receiverEmail) { // make a transaction with Paypal // ... return $success; } function payoneTransaction($amount, $buyerEmail, $receiverEmail) { // make a transaction with Payone // ... return $success; } function informGame($gameId, $userId, $amount) { switch ($gameId) { case 1: $url = 'https://game1.example.com/payment'; $params = ['user' => $userId, 'money' => $amount]; break; case 2: $url = 'https://game2.example.com/payment'; $params = ['player' => $userId, 'gold' => $amount]; break; } $paramStr = []; foreach ($params as $k => $v) { $paramStr[] = "$k=$v"; } return file_get_contents($url.'?'.implode('&', $paramStr)); } // do some payment $gameId = (int)$_POST['game']; $userId = (int)$_POST['user']; $buyer = $_POST['buyer']; $amount = abs((int)$_POST['amount']); $method = $_POST['method']; $success = false; switch ($method) { case 'paypal': $success = paypalTransaction($amount, $buyer, $globalConfig['paypalAccountEmail']); break; case 'payone': $success = payoneTransaction($amount, $buyer, $globalConfig['payoneAccountEmail']); break; } if ($success) { $gameResponse = informGame($gameId, $userId, $amount); if ($gameResponse != 'ok') { logError('Game failed!'); } } else { logError('Bad news!'); } |
Hier haben wir also die Grundzüge einer Bezahlfunktion. Zunächst muss das Geld transferiert werden und anschließend – je nach Erfolg – wird einem Spieler etwas in einem Spiel gutgeschrieben. Es müssen also verschiedene Entscheidungen anhand von Eingangsparametern getroffen werden (switch
). Eine Erweiterung an dieser Stelle, bedeutet einen weiteren case
anzulegen.
Nun die Variante in OOP.
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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
class TransactionException extends Exception {} abstract class Transaction { protected $amount, $buyerEmail, $receiverEmail; public function setAmount($amount) { $this->amount = $amount; return $this; } public function setBuyerEmail($buyerEmail) { $this->buyerEmail = $buyerEmail; return $this; } public function setReceiverEmail($receiverEmail) { $this->receiverEmail = $receiverEmail; return $this; } protected function checkInput() { if ($this->amount <= 0) { throw new TransactionException('Negative Amount'); } // more checks ... } final public function execute() { $this->checkInput(); $this->sendRequest(); } /** * @param string $type * * @throws TransactionException * @return self */ public static function factory($type) { $className = ucfirst($type).'Transaction'; if (!class_exists($className, true)) { throw new TransactionException("Undefined type: $type"); } return new $className(); } abstract protected function sendRequest(); } class PaypalTransaction extends Transaction { protected function sendRequest() { // make a transaction if (!$success) { throw new TransactionException('Failed to contact Paypal'); } } } class PayoneTransaction extends Transaction { protected function sendRequest() { // ... } } class CommunicatorException extends Exception {} abstract class Communicator { protected $userId, $amount; public function informGame($userId, $amount) { $this->userId = (int)$userId; $this->amount = (int)$amount; $paramStr = []; foreach ($this->getParams() as $k => $v) { $paramStr[] = "$k=$v"; } $success = file_get_contents($this->getUrl().'?'.implode('&', $paramStr)); if ($success != 'ok') { throw new CommunicatorException('Game did not respond.'); } } /** * @param $gameId * * @return self * @throws CommunicatorException */ public static function factory($gameId) { $className = 'Game'.((int)$gameId).'Communicator'; if (!class_exists($className, true)) { throw new CommunicatorException("Undefined Game: $gameId"); } return new $className(); } abstract protected function getUrl(); abstract protected function getParams(); } class Game1Communicator extends Communicator { protected function getUrl() { return 'https://game1.example.com/payment'; } protected function getParams() { return ['user' => $this->userId, 'money' => $this->amount]; } } class Game2Communicator extends Communicator { protected function getUrl() { return 'https://game2.example.com/payment'; } protected function getParams() { return ['player' => $this->userId, 'gold' => $this->amount]; } } class Payment { /** @var Transaction */ private $transaction; /** @var Communicator */ private $communicator; public function __construct(Transaction $transaction, Communicator $communicator) { $this->transaction = $transaction; $this->communicator = $communicator; } public function handle($userId, $amount) { try { $this->transaction->execute(); $this->communicator->informGame($userId, $amount); } catch (TransactionException $e) { // some logging } catch (CommunicatorException $e) { // some logging } } } // do some payment $communicator = Communicator::factory($_POST['game']); $transaction = Transaction::factory($_POST['method']); $payment = new Payment($transaction, $communicator); $payment->handle($_POST['user'], $_POST['amount']); |
Für eine Erweiterung muss jetzt lediglich einen neue Klasse angelegt werden. Die übergeordnete abstrakte Klasse diktiert dabei notwendige Funktionen und sorgt dafür das wichtige Checks im Vorfeld ausgeführt werden. Durch Exceptions wird die Ablaufkontrolle vereinfacht.
Ein Gedanke zu „Ein Beispiel zur Objektorientierung“
Kommentare sind geschlossen.