Design patterns:
Factory pattern
<?php
interface Product {
function getPrice ();
function getPicture ();
function getDescription ();
}
?>
<?php
class Mouse implements Product {
public function getDescription () {
}
public function getPicture () {
}
public function getPrice () {
}
}
?>
<?php
class Keyboard implements Product {
public function getDescription () {
return "simple description" ;
}
public function getPicture () {
return null ;
}
public function getPrice () {
return 50 ;
}
}
?>
<?php
class ProductFactory {
function make ( $productId ) {
if ( $this -> isKeyboard ( $productId ))
return new Keyboard ();
return new Mouse ();
}
private function isKeyboard ( $productId ) {
return substr ( $productId , 0 , 1 ) == 'k' ;
}
}
?>
<?php
class ShoppingCart {
private $productsInTheCart = array ();
private $productFactory ;
public function __construct () {
$this -> productFactory = new ProductFactory ();
}
function add ( $productId ) {
$this -> productsInTheCart [] = $this -> productFactory -> make ( $productId );
}
}
?>
Gateway pattern
<?php
interface CartGateway {
function persist ( ShoppingCart $cart );
function retrieve ( $id );
function getIdOfRecordedCart ();
}
?>
<?php
class FileCart implements CartGateway {
private $fileId ;
public function __construct () {
$this -> fileId = uniqid ();
}
public function getIdOfRecordedCart () {
return $this -> fileId ;
}
public function persist ( ShoppingCart $cart ) {
file_put_contents ( $this -> fileId , serialize ( $cart ));
}
public function retrieve ( $id ) {
return unserialize ( file_get_contents ( $id ));
}
}
?>
<?php
class InMemoryCart implements CartGateway {
private $listOfCarts = array ();
public function getIdOfRecordedCart () {
return end ( $this -> listOfCarts );
}
public function persist ( ShoppingCart $cart ) {
$this -> listOfCarts [] = $cart ;
}
public function retrieve ( $id ) {
return $this -> listOfCarts [ $id ];
}
}
?>
<?php
class ShoppingHistory {
private $gateway ;
private $shoppingCartIds = array ();
public function __construct ( CartGateway $gateway , $ids = array ()) {
$this -> gateway = $gateway ;
$this -> shoppingCartIds = $ids ;
}
function listAllCarts () {
$shoppingCarts = array ();
foreach ( $this -> shoppingCartIds as $id ) {
$shoppingCarts [] = $this -> gateway -> retrieve ( $id );
}
return $shoppingCarts ;
}
}
?>
Proxy pattern
<?php
interface Cart {
function getProducts ();
}
?>
<?php
class ShoppingCart implements Cart {
private $products ;
public function getProducts () {
return $this -> products ;
}
}
?>
<?php
require_once './ShoppingCart.php' ;
class CartProxy implements Cart {
private $shoppinCart ;
public function getProducts () {
if ( is_null ( $this -> shoppinCart ))
$this -> shoppingCart = $gateway -> getCarts ();
return $this -> shoppingCart -> getProducts ();
}
}
?>
Repository pattern
<?php
class ProductType {
private $category ;
private $name ;
private $code ;
public function __construct ( $category , $name , $code ) {
$this -> category = $category ;
$this -> name = $name ;
$this -> code = $code ;
}
function __get ( $typeProperty ) {
if ( ! isset ( $this -> $typeProperty ))
throw new Exception ( 'No such property' );
return $this -> $typeProperty ;
}
}
?>
<?php
class TypesFactory {
function makeFrom ( $typeData = array ()) {
if ( empty ( $typeData )) return null ;
return new ProductType (
$typeData [ 'category' ], $typeData [ 'name' ], $typeData [ 'code' ]);
}
}
?>
<?php
class TypesGateway {
function retrieveAllTypes () {
// Here should be some complicated logic returning all the tipes.
}
}
?>
<?php
require_once './TypesFactory.php' ;
require_once './TypesGateway.php' ;
class ProductTypes {
private $factory ;
private $gateway ;
public function __construct ( TypesFactory $factory , TypesGateway $gateway ) {
$this -> factory = $factory ;
$this -> gateway = $gateway ;
}
function findAll () {
$allTypes = array ();
$allTypes = $this -> gateway -> retrieveAllTypes ();
return $this -> makeAllForTypes ( $allTypes );
}
function findComputerHardware () {
$allTypes = $this -> gateway -> retrieveAllTypes ();
$hardwareTypes = array_filter ( $allTypes , function ( $item ) {
return $item [ 'group' ] == 'CmputerHardware' ;
});
return $this -> makeAllForTypes ( $hardwareTypes );
}
private function makeAllForTypes ( $allTypes ) {
$types = array ();
foreach ( $allTypes as $typeData ) {
$types [] = $this -> factory -> makeFrom ( $typeData );
}
return $types ;
}
}
?>
Null pattern
<?php
class NullProduct implements Product {
public function getDescription () {
return '' ;
}
public function getPicture () {
return '/img/default.png' ;
}
public function getPrice () {
return 0 ;
}
}
?>
<?php
require_once 'NullProduct.php' ;
// Provides products of different types.
// This may be a gateway, a repository or a dabatase access layer. Doesn't matter.
class ProductProvider {
function findProduct ( $id ) {
if ( $id == 0 )
return new Keyboard ();
return new NullProduct ();
}
}
?>
<?php
require_once __DIR__ . '/../Factory/Product.php' ;
require_once 'ProductProvider.php' ;
class Receipt {
private $total ;
function addProductById ( $id ) {
$provider = new ProductProvider ();
$product = $provider -> findProduct ( $id );
$this -> addToTotal ( $product );
}
function addToTotal ( Product $product ) {
$this -> total += $product -> getPrice ();
}
function getTotalPrice () {
return $this -> total ;
}
}
?>
<?php
require_once '../Receipt.php' ;
require_once '../../Factory/Keyboard.php' ;
class NullObjectPatternTest extends PHPUnit_Framework_TestCase {
function testNullBehavior () {
$this -> assertEquals ( 2 , null + 2 );
$this -> assertEquals ( 'nothing' , null . 'nothing' );
$this -> assertTrue ( null == 0 );
$this -> assertTrue ( null < - 1 );
$this -> assertFalse ( null && false );
//$this->assertFalse(null);
//$this->assertTrue(true && null);
if ( null ) // should this be false or true?
echo 'Inside IF statement' ;
else
echo 'Inside ELSE' ;
//$this->assertTrue(is_object(null));
}
function testReceiptCanAddProductsToItTotal () {
$receipt = new Receipt ();
$product = new Keyboard ();
$receipt -> addToTotal ( $product );
$this -> assertEquals ( 50 , $receipt -> getTotalPrice ());
$receipt -> addProductById ( 1 );
$this -> assertEquals ( 50 , $receipt -> getTotalPrice ());
}
}
?>
Command pattern
<?php
interface PaymentMethod_Y {
function execute ();
}
?>
<?php
class PaymentProcessingException extends Exception {
public function __construct ( $message ) {
parent :: __construct ( $message );
}
}
?>
<?php
require_once 'PaymentMethod.php' ;
class PayPalPayment implements PaymentMethod {
public function execute () {
}
public function __toString () {
return 'PayPal' ;
}
}
?>
<?php
class VisaPayment implements PaymentMethod {
public function execute () {
// Here would be a lot of logic about how to pay for a product with VISA
}
}
?>
<?php
class User {
private $paymentMethod ;
function getPaymentMethod () {
return $this -> paymentMethod ;
// VisaPayment or PayPalPayment
}
}
?>
<?php
require_once 'User.php' ;
require_once 'PaymentMethod.php' ;
require_once 'PaymentProcessingException.php' ;
class ProcessPayment {
function processUserPayment ( $userName ) {
$user = new User ( $userName );
$paymentMethod = $user -> getPaymentMethod ();
$this -> executePayment ( $paymentMethod );
}
private function executePayment ( PaymentMethod $paymentMethod ) {
try {
$paymentMethod -> execute ();
} catch ( Exception $e ) {
throw new PaymentProcessingException (
'Paying with ' . $paymentMethod .
' has failed with error: ' . $e -> message
);
}
}
}
?>
Active object pattern
<?php
class UploaderCommand {
private $size ;
private $chunk ;
private $uploaded ;
private $multiUploader ;
function __construct ( $speed , $size , MultiFileUploader $multiuploader ) {
$this -> size = $size ;
$this -> chunk = $size / $speed ;
$this -> multiUploader = $multiuploader ;
}
function execute () {
$this -> uploaded += $this -> chunk ;
print " \n " . $this -> uploaded . '/' . $this -> size ;
if ( $this -> uploaded < $this -> size )
$this -> multiUploader -> addUPloader ( $this );
}
}
?>
<?php
class MultiFileUploader {
private $uploaders = array ();
function addUPloader ( UploaderCommand $uploader ) {
$this -> uploaders [] = $uploader ;
}
function run () {
while ( ! empty ( $this -> uploaders )) {
$uploader = array_shift ( $this -> uploaders );
$uploader -> execute ();
}
}
}
?>
<?php
require_once '../UploaderCommand.php' ;
require_once '../MultiFileUploader.php' ;
class MultiUploadTest extends PHPUnit_Framework_TestCase {
function testItCanUploadMultipleFiles () {
$multiUploader = new MultiFileUploader ();
$speed = 8 ; $size = 50 ;
$uploaderOne = new UploaderCommand ( $speed , $size , $multiUploader );
$multiUploader -> addUploader ( $uploaderOne );
$speed = 4 ; $size = 20 ;
$uploaderTwo = new UploaderCommand ( $speed , $size , $multiUploader );
$multiUploader -> addUploader ( $uploaderTwo );
$multiUploader -> run ();
}
}
?>
Template pattern
<?php
abstract class Sell {
private $inventory ;
private $paymentProvider ;
public function removeFromInventory () {
$this -> inventory -> remove ( $this );
}
public function retreivePayment () {
$this -> paymentProvider -> retrieve ( $this -> price );
}
}
?>
<?php
require_once 'Sell.php' ;
class SellProducts extends Sell {
private $price ;
private $provider ;
function orderNewItem () {
$this -> provider -> orderNewItem ( $this );
}
}
?>
<?php
require_once 'Sell.php' ;
class SellServices implements Sell {
private $price ;
private $humanResources ;
function markHumanResourcesAsOccupied () {
$this -> humanResources -> mark ( 2 );
}
}
?>
Strategy pattern
<?php
interface PriceCalculator {
function negativeDiscount ( $price );
function calculateTaxes ( $price );
function convertCurrency ( $price );
}
?>
<?php
class GrandPrice {
private $sellerFrom ;
function calculate ( $price , PriceCalculator $pricingStrategy ) {
$grandPrice = $price ;
$grandPrice += $pricingStrategy -> negativeDiscount ( $price );
$grandPrice += $pricingStrategy -> calculateTaxes ( $price );
$grandPrice = $pricingStrategy -> convertCurrency ( $price );
return $grandPrice ;
}
}
?>
<?php
class EuropePricingStrategy implements PriceCalculator {
function convertCurrency ( $price ) {
return $price * 0.70 ;
}
public function calculateTaxes ( $price ) {
return $price * 20 / 100 ;
}
public function negativeDiscount ( $price ) {
if ( $price > 1000 )
return - 100 ;
return - 10 ;
}
}
?>
<?php
class USAPricingStrategy implements PriceCalculator {
public function calculateTaxes ( $price ) {
return $price * 5 / 100 ;
}
public function convertCurrency ( $price ) {
return $price * 1 ;
}
public function negativeDiscount ( $price ) {
return - 50 ;
}
}
?>
Facade pattern
<?php
class ClientData {
}
?>
<?php
class TopPayments {
function findMaxForClientWithId ( $clientId ) {
return 150 ;
}
}
?>
<?php
class ClientPersonalData {
private $streetAddress ;
private $postalCode ;
private $country ;
public function __construct ( $clienId ) {
// Class will load itself on creation with Active Record
// or some similar pattern and populate it's private variables
}
function getStreetAddress () {
return $this -> streetAddress ;
}
function getPostalCode () {
return $this -> postalCode ;
}
function getCountry () {
return $this -> country ;
}
}
?>
<?php
class ClientFacade {
function getAllClientData ( $clientID ) {
return array (
$clientID ,
$this -> ClientAddress ( $clientID ),
$this -> getMostPayedFor ( $clientID ),
$this -> getPaymentHistory ( $clientId )
);
}
private function ClientAddres ( $clientID ) {
$clientShippingAddress = '' ;
$clientPersonalData = new ClientPersonalData ( $clienId );
$clientShippingAddress = $clientPersonalData -> getAddress ();
$clientShippingAddress . = ',' . $clientPersonalData -> getCountry ();
$clientShippingAddress . = ',' . $clientPersonalData -> getPostalCode ();
return $clientShippingAddress ;
}
private function getMostPayedFor ( $clientId ) {
$topPayments = new TopPayments ();
return $topPayments -> findMaxForClientWithId ( $clientId );
}
private function getPaymentHistory ( $clientID ) {
$paymentHIstory = new PaymentHistory ();
return $paymentHIstory -> findPaymentsForClient ( $clientId );
}
}
?>
<?php
class PaymentHistory {
function findPaymentsForClient ( $clientId ) {
return array ( 50 , 150 , 20 , 15 );
}
}
?>
<?php
class Statistics {
private $clientData ;
private $facade ;
public function __construct ( ClientFacade $facade ) {
$this -> clientData = new ClientData ();
$this -> facade = $facade ;
}
function loadAllClientStats ( $clientId ) {
$allClientDataArray = $this -> facade -> getAllClientData ( $clientID );
$this -> clientData -> id = $allClientDataArray [ 0 ];
$this -> clientData -> address = $allClientDataArray [ 1 ];
$this -> clientData -> mostPaydFor = $allClientDataArray [ 2 ];
$this -> clientData -> userHistory = $allClientDataArray [ 3 ];
}
}
?>
Observer pattern
<?php
interface ProductObserver {
function update ();
}
?>
<?php
abstract class ProductSubject {
private $observers = array ();
function register ( ProductObserver $observer ) {
$this -> observers [] = $observer ;
}
protected function notify () {
foreach ( $this -> observers as $observer )
$observer -> update ();
}
}
?>
<?php
require_once __DIR__ . '/ProductObserver.php' ;
require_once __DIR__ . '/ProductSubject.php' ;
class Notifier implements ProductObserver {
private $product ;
function __construct ( ProductSubject $subject ) {
$this -> product = $subject ;
}
public function update () {
$newPrice = $this -> product -> getPrice ();
// some kind of notification
}
}
?>
<?php
require_once __DIR__ . '/ProductSubject.php' ;
class HardDisk extends ProductSubject {
private $price ;
function setPrice ( $price ) {
$this -> price = $price ;
$this -> notify ();
}
function getPrice () {
return $this -> price ;
}
}
?>
<?php
require_once '../Notifier.php' ;
require_once '../HardDisk.php' ;
class ObserverTest extends PHPUnit_Framework_TestCase {
function testItCanNotify () {
$product = new HardDisk ();
$mailNotifier = new Notifier ( $product );
$product -> register ( $mailNotifier );
}
}
?>
Mediator pattern
<?php
interface UserAddress {
function setAddress ();
}
?>
<?php
abstract class Observable {
private $observers = array ();
function register ( $observer ) {
$this -> observers [] = $observer ;
}
private function notify ( $hint ) {
foreach ( $this -> observers as $observer ) {
$observer -> update ( $hint );
}
}
}
?>
<?php
require_once './Observable.php' ;
require_once './UserAddress.php' ;
class Mediator {
private $observedClass ;
private $affectedClass ;
function __construct ( Observable $observedClass , UserAddress $affectedClass ) {
$this -> observedClass = $observedClass ;
$this -> affectedClass = $affectedClass ;
$observedClass -> register ( $this );
}
function update ( $address ) {
$this -> affectedClass -> setAddress ( $address );
}
}
?>
<?php
class OrderDelivery implements UserAddress {
private $deliveryAddress ;
public function setAddress ( $newAddress ) {
$this -> deliveryAddress = $newAddress ;
}
}
?>
<?php
class UserDetails extends Observable {
private $address ;
function cangeAddress ( $newAddress ) {
$this -> address = $newAddress ;
$this -> notify ( $newAddress );
}
}
?>
<?php
require_once './UserDetails.php' ;
class UserUpdater {
function updateUserAddress ( $newAddress ) {
$user = new UserDetails ();
$user -> cangeAddress ( $newAddress );
}
}
?>
Singleton pattern
<?php
class DiscountProvider {
private static $instance = null ;
private function __construct () {
// here would be some complicated init logic
}
static function getInstance () {
if ( self :: $instance == NULL )
self :: $instance = new DiscountProvider ();
return self :: $instance ;
}
function getDiscountFor ( $product ) {
// it would return the discounted price as percentage
return 30 ;
}
}
?>
<?php
class PriceCalculator {
function compute ( Product $product ) {
$discountProvider = DiscountProvider :: getInstance ();
$discountAsPercent = $discountProvider -> getDiscountFor ( $product - getId ());
$price = $product -> getPrice ();
$discountAsValue = $price * $discountAsPercent ;
return $price - $discountAsValue ;
}
}
?>
Monostate pattern
<?php
class Monostate {
private static $value ; // Static value
function setValue ( $value ) { // Dynamic function
self :: $value = $value ; // Static value
}
function getValue () { // Dynamic function
return self :: $value ; // Static value
}
}
?>
<?php
require_once '../Monostate.php' ;
class MonostateTest extends PHPUnit_Framework_TestCase {
function testMonostate () {
$firstObject = new Monostate ();
$secondObject = new Monostate ();
$firstObject -> setValue ( '10' );
$this -> assertEquals ( 10 , $firstObject -> getValue ());
$this -> assertEquals ( 10 , $secondObject -> getValue ());
$this -> assertEquals ( 10 , $thirdObject -> getValue ());
}
}
?>
Abstract server pattern
<?php
interface Roses {
function sell ();
function isSold ();
}
?>
<?php
require_once __DIR__ . '/Roses.php' ;
class RedRose implements Roses {
private $sold = false ;
function sell () {
$this -> sold = true ;
}
function isSold () {
return $this -> sold ;
}
}
?>
<?php
class YellowRose implements Roses {
private $sold = false ;
function sell () {
$this -> sold = true ;
}
function isSold () {
return $this -> sold ;
}
}
?>
<?php
require_once __DIR__ . '/RedRose.php' ;
class ShopOwner {
private $rose ;
function __construct ( Roses $rose ) {
$this -> rose = $rose ;
}
function sell () {
$this -> rose -> sell ();
}
}
?>
<?php
require_once '../RedRose.php' ;
require_once '../YellowRose.php' ;
require_once '../ShopOwner.php' ;
class ShopOwnerTest extends PHPUnit_Framework_TestCase {
function testOwnerCanSellRedRoses () {
$redRose = new RedRose ();
$shopOwner = new ShopOwner ( $redRose );
$shopOwner -> sell ();
$this -> assertTrue ( $redRose -> isSold ());
}
function testOwnerCanSellYellowRoses () {
$yellowRose = new YellowRose ();
$shopOwner = new ShopOwner ( $yellowRose );
$shopOwner -> sell ();
$this -> assertTrue ( $yellowRose -> isSold ());
}
}
?>
Adapter pattern
<?php
interface ProductInterface {
function getDescription ();
function getPrice ();
function getPicture ();
function sell ();
}
?>
<?php
interface TheOldRosesInterface {
function sell ();
function showImage ();
function getPriceFromDatabase ();
}
?>
<?php
class RealWhiteRose implements TheOldRosesInterface {
public function getPriceFromDatabase () {
}
public function sell () {
}
public function showImage () {
}
}
?>
<?php
class RosesToProductAdapter implements ProductInterface {
private $rose ;
function _construct ( TheOldRosesInterface $rose ) {
$this -> rose = $rose ;
}
public function getDescription () {
return 'Nice flowers' ;
}
public function getPicture () {
return $this -> rose -> showImage ();
}
public function getPrice () {
return $this -> rose -> getPriceFromDatabase ();
// Formatting and currency calculations may be involved.
}
public function sell () {
return $this -> rose -> sell ();
}
}
?>
Bridge pattern
<?php
interface PaymentSource {
function approve ();
function send ();
}
?>
<?php
interface CreditPayment {
function approve ();
function send ();
}
?>
<?php
class Visa implements PaymentSource {
public function approve () {
// Talk to the bank and approve the sum
}
public function send () {
// Transfer the money
}
}
?>
<?php
class CreditBuyer {
function payNOw ( CreditPayment $payment ) {
if ( $payment -> approve ())
$payment -> send ();
}
}
?>
<?php
class CreditPaymentMethod extends PaymentMethod {
function approve () {
parent :: approveImp ();
}
function send () {
parent :: sendImp ();
}
}
?>
<?php
interface DirectPayment {
function send ();
}
?>
<?php
class DirectBuyer {
function payNow ( DirectPayment $payment ) {
$payment -> send ();
}
}
?>
<?php
class DirectPaymentMethod extends PaymentMethod {
public function approve () {
return true ;
}
public function send () {
parent :: sendImp ();
}
}
?>
<?php
class Mastercard implements PaymentSource {
public function approve () {
}
public function send () {
}
}
?>
<?php
abstract class PaymentMethod_X implements DirectPayment , CreditPayment {
abstract function approve ();
abstract function send ();
private $paymentSource ;
function setPaymentSource ( PaymentSource $paymentSource ) {
$this -> paymentSource = $paymentSource ;
}
protected function sendImp () {
$this -> paymentSource -> send ();
}
protected function approveImp () {
$this -> paymentSource -> approve ();
}
}
?>
Composite pattern
<?php
interface Order {
function place ();
}
?>
<?php
class ProductOrder implements Order {
public function place () {
// Talkt to warehouse.
}
}
?>
<?php
class ServiceOrder implements Order {
public function place () {
// Communicate with HR and require personal for servicing products
}
}
?>
<?php
class CompositeOrder implements Order {
private $orders = array ();
function add ( Order $order ) {
$this -> orders [] = $order ;
}
function place () {
aray_walk ( $this -> orders , function ( $order ) {
$order -> place ();
});
}
}
?>
Visitor pattern
<?php
interface PaymentMethod {
public function getDescription ();
}
?>
<?php
interface PaymentVisitor {
function visit ( PaymentMethod $paymentMethod );
function getDescription ();
}
?>
<?php
require_once 'PaymentVisitor.php' ;
class HtmlPaymentDetails implements PaymentVisitor {
private $description ;
public function getDescription () {
return $this -> description ;
}
public function visit ( PaymentMethod $paymentMethod ) {
$this -> description = '<html><body><div>' .
$paymentMethod -> getDescription () .
'</div></body></html>' ;
}
}
?>
<?php
class PaypalPayment implements PaymentMethod {
public function getDescription () {
return "PaypalDescription" ;
}
function accept ( PaymentVisitor $paymentVisitor ) {
$paymentVisitor -> visit ( $this );
}
}
?>
<?php
require_once 'PaymentVisitor.php' ;
class SimplePaymentDetails implements PaymentVisitor {
private $description ;
public function getDescription () {
return $this -> description ;
}
public function visit ( PaymentMethod $paymentMethod ) {
$this -> description = $paymentMethod -> getDescription ();
}
}
?>
<?php
require_once 'PaymentMethod.php' ;
class VisaPayment implements PaymentMethod {
public function getDescription () {
return "VisaDescription" ;
}
function accept ( PaymentVisitor $paymentVisitor ) {
$paymentVisitor -> visit ( $this );
}
}
?>
<?php
require_once '../VisaPayment.php' ;
require_once '../PaypalPayment.php' ;
require_once '../SimplePaymentDetails.php' ;
require_once '../HtmlPaymentDetails.php' ;
class VisitorTest extends PHPUnit_Framework_TestCase {
function testItCanProvideSimpleDescripion () {
$simpleDetails = new SimplePaymentDetails ();
$visaPayment = new VisaPayment ();
$visaPayment -> accept ( $simpleDetails );
$this -> assertEquals ( 'VisaDescription' , $simpleDetails -> getDescription ());
}
function testItCanProvideHtmlDescripion () {
$htmlDetails = new HtmlPaymentDetails ();
$visaPayment = new VisaPayment ();
$visaPayment -> accept ( $htmlDetails );
$this -> assertEquals (
'<html><body><div>VisaDescription</div></body></html>' ,
$htmlDetails -> getDescription ());
}
}
?>
State pattern
<?php
interface DeliveryState {
function goNext ( Delivery $delivery );
function getLocation ();
}
?>
<?php
class Delivery {
private $currentState ;
function __construct ( DeliveryState $state ) {
$this -> setState ( $state );
}
function getCurrentLocation () {
return $this -> currentState -> getLocation ();
}
function goNext () {
$this -> currentState -> goNext ( $this );
}
function setState ( DeliveryState $state ) {
$this -> currentState = $state ;
}
}
?>
<?php
class AtDestination implements DeliveryState {
public function getLocation () {
return 'Final Destination' ;
}
public function goNext ( Delivery $delivery ) {
$delivery -> setState ( new AtDestination ());
}
}
?>
<?php
class DeliveryUpdater {
}
?>
<?php
require_once 'AtDestination.php' ;
class OnRoute implements DeliveryState {
public function getLocation () {
return 'On the train' ;
}
public function goNext ( Delivery $delivery ) {
$delivery -> setState ( new AtDestination ());
}
}
?>
<?php
class OrderTracker {
}
?>
<?php
require_once 'Delivery.php' ;
require_once 'DeliveryState.php' ;
require_once 'OnRoute.php' ;
class Processing implements DeliveryState {
public function getLocation () {
return 'Warehouse' ;
}
public function goNext ( Delivery $delivery ) {
$delivery -> setState ( new OnRoute ());
}
}
?>
<?php
require_once '../Delivery.php' ;
require_once '../Processing.php' ;
class DeliveryStateTest extends PHPUnit_Framework_TestCase {
function testItCanCreateADEliveryWithInitialState () {
$delivery = new Delivery ( new Processing ());
$this -> assertEquals ( 'Warehouse' , $delivery -> getCurrentLocation ());
}
function testItCanGoFromProcessingToOnRoute () {
$delivery = new Delivery ( new Processing ());
$delivery -> goNext ();
$this -> assertEquals ( 'On the train' , $delivery -> getCurrentLocation ());
}
function testItCanGoFromOnRouteToDestination () {
$delivery = new Delivery ( new OnRoute ());
$delivery -> goNext ();
$this -> assertEquals ( 'Final Destination' , $delivery -> getCurrentLocation ());
}
function testItRemainsAtFinalDestination () {
$delivery = new Delivery ( new AtDestination ());
$delivery -> goNext ();
$this -> assertEquals ( 'Final Destination' , $delivery -> getCurrentLocation ());
}
}
?>
Decorator pattern
<?php
interface PaymentMethod {
public function getDescription ();
}
?>
<?php
class PaypalPayment implements PaymentMethod {
public function getDescription () {
return 'PaypalDescription' ;
}
}
?>
<?php
require_once 'PaymentMethod.php' ;
class VisaPayment implements PaymentMethod {
public function getDescription () {
return 'VisaDescription' ;
}
}
?>
<?php
require_once 'PaymentMethod.php' ;
abstract class PaymentDecorator implements PaymentMethod {
protected $itsPaymentMethod ;
function __construct ( PaymentMethod $paymentMethod ) {
$this -> itsPaymentMethod = $paymentMethod ;
}
public function getDescription () {
return $this -> itsPaymentMethod -> getDescription ();
}
}
?>
<?php
require_once 'PaymentDecorator.php' ;
class HtmlPaymentDetails extends PaymentDecorator {
function getHtmlDescription () {
return '<html>' . $this -> itsPaymentMethod -> getDescription () . '</html>' ;
}
}
?>
<?php
require_once '../VisaPayment.php' ;
require_once '../HtmlPaymentDetails.php' ;
class VisitorTest extends PHPUnit_Framework_TestCase {
function testItCanProvideDescription () {
$visaPayment = new VisaPayment ();
$htmlDetails = new HtmlPaymentDetails ( $visaPayment );
$this -> assertEquals ( 'VisaDescription' , $htmlDetails -> getDescription ());
$this -> assertEquals ( '<html>VisaDescription</html>' , $htmlDetails -> getHtmlDescription ());
}
}
?>