Structural Patterns - PHP Examples
6. Adapter
Mục đích: Chuyển đổi interface của class thành interface khác mà client
mong đợi.
Cách hoạt động: Wrapper class chuyển đổi interface không tương thích.
<?php
// Target Interface
interface PaymentGateway {
public function pay(float $amount): string;
}
// Adaptee (third-party library)
class StripeAPI {
public function makePayment(int $cents): string {
return "Stripe processed {$cents} cents";
}
}
// Adapter
class StripeAdapter implements PaymentGateway {
private $stripe;
public function __construct(StripeAPI $stripe) {
$this->stripe = $stripe;
}
public function pay(float $amount): string {
$cents = (int)($amount * 100);
return $this->stripe->makePayment($cents);
}
}
// Usage
$stripe = new StripeAPI();
$adapter = new StripeAdapter($stripe);
echo $adapter->pay(50.99); // Converts $50.99 to 5099 cents
Khi nào dùng:
Tích hợp thư viện bên thứ 3
Legacy code integration
Ví dụ: Payment gateways, API wrappers, Database adapters
7. Bridge
Mục đích: Tách abstraction khỏi implementation để cả hai có thể thay đổi
độc lập.
Cách hoạt động: Composition thay vì inheritance.
<?php
// Implementation Interface
interface MessageSender {
public function send(string $message): string;
}
// Concrete Implementations
class EmailSender implements MessageSender {
public function send(string $message): string {
return "Email: {$message}";
}
}
class SMSSender implements MessageSender {
public function send(string $message): string {
return "SMS: {$message}";
}
}
// Abstraction
abstract class Notification {
protected $sender;
public function __construct(MessageSender $sender) {
$this->sender = $sender;
}
abstract public function notify(string $message): string;
}
// Refined Abstractions
class UrgentNotification extends Notification {
public function notify(string $message): string {
return $this->sender->send("[URGENT] " . $message);
}
}
class RegularNotification extends Notification {
public function notify(string $message): string {
return $this->sender->send($message);
}
}
// Usage
$emailNotification = new UrgentNotification(new EmailSender());
echo $emailNotification->notify("Server down!") . "\n";
$smsNotification = new RegularNotification(new SMSSender());
echo $smsNotification->notify("Hello!");
Khi nào dùng:
Tránh explosion của subclasses
Muốn thay đổi implementation runtime
Ví dụ: UI themes, Database drivers, Notification systems
8. Composite
Mục đích: Tổ chức objects thành cấu trúc cây để xử lý individual và
composite objects giống nhau.
Cách hoạt động: Tree structure với leaf và composite nodes.
<?php
// Component Interface
interface FileSystemComponent {
public function getSize(): int;
public function getName(): string;
}
// Leaf
class File implements FileSystemComponent {
private $name;
private $size;
public function __construct(string $name, int $size) {
$this->name = $name;
$this->size = $size;
}
public function getSize(): int {
return $this->size;
}
public function getName(): string {
return $this->name;
}
}
// Composite
class Directory implements FileSystemComponent {
private $name;
private $children = [];
public function __construct(string $name) {
$this->name = $name;
}
public function add(FileSystemComponent $component) {
$this->children[] = $component;
}
public function getSize(): int {
$total = 0;
foreach ($this->children as $child) {
$total += $child->getSize();
}
return $total;
}
public function getName(): string {
return $this->name;
}
}
// Usage
$root = new Directory("root");
$root->add(new File("[Link]", 100));
$root->add(new File("[Link]", 200));
$subDir = new Directory("documents");
$subDir->add(new File("[Link]", 500));
$root->add($subDir);
echo "Total size: " . $root->getSize() . " bytes"; // 800
Khi nào dùng:
File systems
Menu structures
Organization hierarchies
Ví dụ: Category trees, Comment threads, UI components
9. Decorator
Mục đích: Thêm chức năng mới cho object động mà không thay đổi
structure.
Cách hoạt động: Wrapping objects với decorators.
<?php
// Component Interface
interface Coffee {
public function getCost(): float;
public function getDescription(): string;
}
// Concrete Component
class SimpleCoffee implements Coffee {
public function getCost(): float {
return 10;
}
public function getDescription(): string {
return "Simple coffee";
}
}
// Base Decorator
abstract class CoffeeDecorator implements Coffee {
protected $coffee;
public function __construct(Coffee $coffee) {
$this->coffee = $coffee;
}
}
// Concrete Decorators
class MilkDecorator extends CoffeeDecorator {
public function getCost(): float {
return $this->coffee->getCost() + 2;
}
public function getDescription(): string {
return $this->coffee->getDescription() . ", milk";
}
}
class SugarDecorator extends CoffeeDecorator {
public function getCost(): float {
return $this->coffee->getCost() + 1;
}
public function getDescription(): string {
return $this->coffee->getDescription() . ", sugar";
}
}
// Usage
$coffee = new SimpleCoffee();
echo $coffee->getDescription() . " = $" . $coffee->getCost() . "\n";
$coffeeWithMilk = new MilkDecorator($coffee);
echo $coffeeWithMilk->getDescription() . " = $" . $coffeeWithMilk-
>getCost() . "\n";
$coffeeWithMilkAndSugar = new SugarDecorator($coffeeWithMilk);
echo $coffeeWithMilkAndSugar->getDescription() . " = $" .
$coffeeWithMilkAndSugar->getCost();
Khi nào dùng:
Thêm features động
Alternative cho subclassing
Ví dụ: Middleware, Stream filters, UI components
10. Facade
Mục đích: Cung cấp interface đơn giản cho hệ thống phức tạp.
Cách hoạt động: Unified interface che giấu complexity.
<?php
// Complex subsystems
class VideoFile {
private $filename;
public function __construct(string $filename) {
$this->filename = $filename;
}
public function getFilename(): string {
return $this->filename;
}
}
class CodecFactory {
public function extract(VideoFile $file): string {
return "Extracting codec from {$file->getFilename()}";
}
}
class BitrateReader {
public function read(VideoFile $file): string {
return "Reading bitrate of {$file->getFilename()}";
}
}
class AudioMixer {
public function fix(VideoFile $file): string {
return "Fixing audio of {$file->getFilename()}";
}
}
// Facade
class VideoConverter {
public function convert(string $filename, string $format): string
{
$file = new VideoFile($filename);
$codec = new CodecFactory();
$bitrate = new BitrateReader();
$audio = new AudioMixer();
$result = [];
$result[] = $codec->extract($file);
$result[] = $bitrate->read($file);
$result[] = $audio->fix($file);
$result[] = "Converting to {$format}";
return implode("\n", $result);
}
}
// Usage
$converter = new VideoConverter();
echo $converter->convert("video.mp4", "avi");
Khi nào dùng:
Simplify complex APIs
Provide entry point to subsystem
Ví dụ: Library wrappers, Service layers, Framework facades
11. Flyweight
Mục đích: Tiết kiệm bộ nhớ bằng cách chia sẻ data giữa nhiều objects.
Cách hoạt động: Tách intrinsic (shared) và extrinsic (unique) state.
<?php
// Flyweight
class TreeType {
private $name;
private $color;
private $texture;
public function __construct(string $name, string $color, string
$texture) {
$this->name = $name;
$this->color = $color;
$this->texture = $texture;
}
public function render(int $x, int $y): string {
return "Drawing {$this->name} tree at ({$x}, {$y})";
}
}
// Flyweight Factory
class TreeFactory {
private static $treeTypes = [];
public static function getTreeType(string $name, string $color,
string $texture): TreeType {
$key = md5($name . $color . $texture);
if (!isset(self::$treeTypes[$key])) {
self::$treeTypes[$key] = new TreeType($name, $color,
$texture);
}
return self::$treeTypes[$key];
}
public static function getCount(): int {
return count(self::$treeTypes);
}
}
// Context
class Tree {
private $x;
private $y;
private $type;
public function __construct(int $x, int $y, TreeType $type) {
$this->x = $x;
$this->y = $y;
$this->type = $type;
}
public function render(): string {
return $this->type->render($this->x, $this->y);
}
}
// Usage
$forest = [];
$forest[] = new Tree(10, 20, TreeFactory::getTreeType("Oak", "Green",
"Rough"));
$forest[] = new Tree(30, 40, TreeFactory::getTreeType("Oak", "Green",
"Rough"));
$forest[] = new Tree(50, 60, TreeFactory::getTreeType("Pine", "Dark
Green", "Smooth"));
foreach ($forest as $tree) {
echo $tree->render() . "\n";
}
echo "Total tree types created: " . TreeFactory::getCount(); // Only 2
instead of 3
Khi nào dùng:
Nhiều objects tương tự nhau
Memory optimization
Ví dụ: Game objects, Text formatting, Caching
12. Proxy
Mục đích: Cung cấp placeholder/surrogate cho object khác để kiểm soát
access.
Cách hoạt động: Wrapper kiểm soát access đến real object.
<?php
// Subject Interface
interface Image {
public function display(): string;
}
// Real Subject
class RealImage implements Image {
private $filename;
public function __construct(string $filename) {
$this->filename = $filename;
$this->loadFromDisk();
}
private function loadFromDisk(): void {
echo "Loading {$this->filename} from disk...\n";
}
public function display(): string {
return "Displaying {$this->filename}";
}
}
// Proxy
class ProxyImage implements Image {
private $filename;
private $realImage = null;
public function __construct(string $filename) {
$this->filename = $filename;
}
public function display(): string {
// Lazy loading
if ($this->realImage === null) {
$this->realImage = new RealImage($this->filename);
}
return $this->realImage->display();
}
}
// Usage
$image1 = new ProxyImage("[Link]");
$image2 = new ProxyImage("[Link]");
// Image not loaded yet
echo $image1->display(); // Loads and displays
echo $image1->display(); // Just displays (already loaded)
Các loại Proxy:
Virtual Proxy: Lazy loading (như ví dụ trên)
Protection Proxy: Access control
Remote Proxy: Đại diện cho remote object
Caching Proxy: Cache results
Khi nào dùng:
Lazy initialization
Access control
Logging/monitoring
Ví dụ: ORM lazy loading, API rate limiting, Image loading