PHP 装饰器模式
目的
动态地为类的实例添加功能
例子
- Web Service层:REST服务的JSON与XML装饰器(当然,在此只能使用其中的一种)
UML 图
代码
Booking.php
<?php declare(strict_types=1); namespace DesignPatterns\Structural\Decorator; interface Booking { public function calculatePrice(): int; public function getDescription(): string; }
BookingDecorator.php
<?php declare(strict_types=1); namespace DesignPatterns\Structural\Decorator; abstract class BookingDecorator implements Booking { public function __construct(protected Booking $booking) { } }
DoubleRoomBooking.php
<?php declare(strict_types=1); namespace DesignPatterns\Structural\Decorator; class DoubleRoomBooking implements Booking { public function calculatePrice(): int { return 40; } public function getDescription(): string { return 'double room'; } }
ExtraBed.php
<?php declare(strict_types=1); namespace DesignPatterns\Structural\Decorator; class ExtraBed extends BookingDecorator { private const PRICE = 30; public function calculatePrice(): int { return $this->booking->calculatePrice() + self::PRICE; } public function getDescription(): string { return $this->booking->getDescription() . ' with extra bed'; } }
WiFi.php
<?php declare(strict_types=1); namespace DesignPatterns\Structural\Decorator; class WiFi extends BookingDecorator { private const PRICE = 2; public function calculatePrice(): int { return $this->booking->calculatePrice() + self::PRICE; } public function getDescription(): string { return $this->booking->getDescription() . ' with wifi'; } }
测试
Tests/DecoratorTest.php
<?php declare(strict_types=1); namespace DesignPatterns\Structural\Decorator\Tests; use DesignPatterns\Structural\Decorator\DoubleRoomBooking; use DesignPatterns\Structural\Decorator\ExtraBed; use DesignPatterns\Structural\Decorator\WiFi; use PHPUnit\Framework\TestCase; class DecoratorTest extends TestCase { public function testCanCalculatePriceForBasicDoubleRoomBooking() { $booking = new DoubleRoomBooking(); $this->assertSame(40, $booking->calculatePrice()); $this->assertSame('double room', $booking->getDescription()); } public function testCanCalculatePriceForDoubleRoomBookingWithWiFi() { $booking = new DoubleRoomBooking(); $booking = new WiFi($booking); $this->assertSame(42, $booking->calculatePrice()); $this->assertSame('double room with wifi', $booking->getDescription()); } public function testCanCalculatePriceForDoubleRoomBookingWithWiFiAndExtraBed() { $booking = new DoubleRoomBooking(); $booking = new WiFi($booking); $booking = new ExtraBed($booking); $this->assertSame(72, $booking->calculatePrice()); $this->assertSame('double room with wifi with extra bed', $booking->getDescription()); } }