多态

什么是多态

多态(Polymorphism)是面向对象编程的四大特性之一。多态意味着"多种形态",在编程中指的是同一个接口或方法,作用于不同的对象时会产生不同的行为。简单来说,多态允许我们使用父类类型的变量来引用子类的对象,并调用子类重写的方法。

多态的核心概念

  • 多种形态:同一操作作用于不同对象,产生不同的执行结果
  • 动态绑定:在运行时确定调用哪个方法
  • 统一接口:通过统一接口处理不同类型的对象
  • 代码灵活性:编写更通用、可扩展的代码

多态的实现方式

1. 通过继承实现多态

<?php
// 基类
class Animal {
    protected $name;

    public function __construct($name) {
        $this->name = $name;
    }

    // 定义通用的发声方法
    public function makeSound() {
        return "动物发出声音";
    }

    public function eat() {
        return "{$this->name} 正在吃东西";
    }
}

// 子类1:狗
class Dog extends Animal {
    public function makeSound() {
        return "{$this->name} 汪汪叫";
    }

    public function fetch() {
        return "{$this->name} 正在捡球";
    }
}

// 子类2:猫
class Cat extends Animal {
    public function makeSound() {
        return "{$this->name} 喵喵叫";
    }

    public function climb() {
        return "{$this->name} 正在爬树";
    }
}

// 子类3:鸟
class Bird extends Animal {
    public function makeSound() {
        return "{$this->name} 叽叽喳喳叫";
    }

    public function fly() {
        return "{$this->name} 正在飞翔";
    }
}

// 多态函数:可以处理任何Animal类型的对象
function makeAnimalSound(Animal $animal) {
    echo $animal->makeSound() . "\n";
}

function letAnimalPerform(Animal $animal) {
    echo $animal->makeSound() . "\n";
    echo $animal->eat() . "\n";

    // 使用instanceof检查具体类型,调用特定方法
    if ($animal instanceof Dog) {
        echo $animal->fetch() . "\n";
    } elseif ($animal instanceof Cat) {
        echo $animal->climb() . "\n";
    } elseif ($animal instanceof Bird) {
        echo $animal->fly() . "\n";
    }
    echo "---\n";
}

// 创建不同的动物对象
$animals = [
    new Dog("旺财"),
    new Cat("咪咪"),
    new Bird("小黄")
];

// 演示多态
echo "=== 动物叫声 ===\n";
foreach ($animals as $animal) {
    makeAnimalSound($animal);
}

echo "\n=== 动物表演 ===\n";
foreach ($animals as $animal) {
    letAnimalPerform($animal);
}
?>

2. 通过接口实现多态

<?php
// 定义支付接口
interface PaymentInterface {
    public function processPayment($amount);
    public function getPaymentStatus();
    public function refund($amount);
}

// 信用卡支付实现
class CreditCardPayment implements PaymentInterface {
    private $cardNumber;
    private $status = 'pending';

    public function __construct($cardNumber) {
        $this->cardNumber = $cardNumber;
    }

    public function processPayment($amount) {
        echo "使用信用卡 {$this->cardNumber} 支付 ¥{$amount}\n";
        $this->status = 'completed';
        return true;
    }

    public function getPaymentStatus() {
        return $this->status;
    }

    public function refund($amount) {
        echo "退款 ¥{$amount} 到信用卡 {$this->cardNumber}\n";
        $this->status = 'refunded';
        return true;
    }
}

// 支付宝支付实现
class AlipayPayment implements PaymentInterface {
    private $accountId;
    private $status = 'pending';

    public function __construct($accountId) {
        $this->accountId = $accountId;
    }

    public function processPayment($amount) {
        echo "使用支付宝账号 {$this->accountId} 支付 ¥{$amount}\n";
        $this->status = 'completed';
        return true;
    }

    public function getPaymentStatus() {
        return $this->status;
    }

    public function refund($amount) {
        echo "退款 ¥{$amount} 到支付宝账号 {$this->accountId}\n";
        $this->status = 'refunded';
        return true;
    }
}

// 微信支付实现
class WechatPayment implements PaymentInterface {
    private $openId;
    private $status = 'pending';

    public function __construct($openId) {
        $this->openId = $openId;
    }

    public function processPayment($amount) {
        echo "使用微信 {$this->openId} 支付 ¥{$amount}\n";
        $this->status = 'completed';
        return true;
    }

    public function getPaymentStatus() {
        return $this->status;
    }

    public function refund($amount) {
        echo "退款 ¥{$amount} 到微信账号 {$this->openId}\n";
        $this->status = 'refunded';
        return true;
    }
}

// 支付处理器类(使用多态)
class PaymentProcessor {
    private $paymentMethods = [];

    // 添加支付方式
    public function addPaymentMethod(PaymentInterface $paymentMethod) {
        $this->paymentMethods[] = $paymentMethod;
    }

    // 处理支付
    public function processAllPayments($amount) {
        foreach ($this->paymentMethods as $paymentMethod) {
            if ($paymentMethod->processPayment($amount)) {
                echo "支付成功!状态:" . $paymentMethod->getPaymentStatus() . "\n";
            } else {
                echo "支付失败!\n";
            }
        }
    }

    // 处理退款
    public function processAllRefunds($amount) {
        foreach ($this->paymentMethods as $paymentMethod) {
            if ($paymentMethod->refund($amount)) {
                echo "退款成功!状态:" . $paymentMethod->getPaymentStatus() . "\n";
            }
        }
    }
}

// 使用示例
echo "=== 支付系统演示 ===\n\n";

$processor = new PaymentProcessor();

// 添加不同的支付方式
$processor->addPaymentMethod(new CreditCardPayment("1234-5678-9012-3456"));
$processor->addPaymentMethod(new AlipayPayment("user@example.com"));
$processor->addPaymentMethod(new WechatPayment("wx_openid_123456"));

// 处理支付
echo "--- 处理支付 ---\n";
$processor->processAllPayments(100);

echo "\n--- 处理退款 ---\n";
$processor->processAllRefunds(50);
?>

多态的实际应用:图形绘制系统

<?php
// 定义图形接口
interface ShapeInterface {
    public function draw();
    public function getArea();
    public function getPerimeter();
    public function resize($factor);
}

// 基础图形类
abstract class Shape implements ShapeInterface {
    protected $color;
    protected $x;
    protected $y;

    public function __construct($color = 'black', $x = 0, $y = 0) {
        $this->color = $color;
        $this->x = $x;
        $this->y = $y;
    }

    public function move($newX, $newY) {
        $this->x = $newX;
        $this->y = $newY;
        echo "图形移动到位置 ({$newX}, {$newY})\n";
    }

    abstract public function draw();
    abstract public function getArea();
    abstract public function getPerimeter();
    abstract public function resize($factor);
}

// 圆形类
class Circle extends Shape {
    private $radius;

    public function __construct($radius, $color = 'red', $x = 0, $y = 0) {
        parent::__construct($color, $x, $y);
        $this->radius = $radius;
    }

    public function draw() {
        echo "绘制一个半径为{$this->radius}的{$this->color}色圆形,位置({$this->x}, {$this->y})\n";
    }

    public function getArea() {
        return pi() * $this->radius * $this->radius;
    }

    public function getPerimeter() {
        return 2 * pi() * $this->radius;
    }

    public function resize($factor) {
        $this->radius *= $factor;
        echo "圆形缩放{$factor}倍,新半径:{$this->radius}\n";
    }
}

// 矩形类
class Rectangle extends Shape {
    private $width;
    private $height;

    public function __construct($width, $height, $color = 'blue', $x = 0, $y = 0) {
        parent::__construct($color, $x, $y);
        $this->width = $width;
        $this->height = $height;
    }

    public function draw() {
        echo "绘制一个{$this->width}x{$this->height}的{$this->color}色矩形,位置({$this->x}, {$this->y})\n";
    }

    public function getArea() {
        return $this->width * $this->height;
    }

    public function getPerimeter() {
        return 2 * ($this->width + $this->height);
    }

    public function resize($factor) {
        $this->width *= $factor;
        $this->height *= $factor;
        echo "矩形缩放{$factor}倍,新尺寸:{$this->width}x{$this->height}\n";
    }
}

// 三角形类
class Triangle extends Shape {
    private $side1;
    private $side2;
    private $side3;

    public function __construct($side1, $side2, $side3, $color = 'green', $x = 0, $y = 0) {
        parent::__construct($color, $x, $y);
        $this->side1 = $side1;
        $this->side2 = $side2;
        $this->side3 = $side3;
    }

    public function draw() {
        echo "绘制一个边长为{$this->side1}, {$this->side2}, {$this->side3}的{$this->color}色三角形,位置({$this->x}, {$this->y})\n";
    }

    public function getArea() {
        // 使用海伦公式计算面积
        $s = ($this->side1 + $this->side2 + $this->side3) / 2;
        return sqrt($s * ($s - $this->side1) * ($s - $this->side2) * ($s - $this->side3));
    }

    public function getPerimeter() {
        return $this->side1 + $this->side2 + $this->side3;
    }

    public function resize($factor) {
        $this->side1 *= $factor;
        $this->side2 *= $factor;
        $this->side3 *= $factor;
        echo "三角形缩放{$factor}倍,新边长:{$this->side1}, {$this->side2}, {$this->side3}\n";
    }
}

// 图形绘制管理器
class DrawingManager {
    private $shapes = [];

    // 添加图形
    public function addShape(ShapeInterface $shape) {
        $this->shapes[] = $shape;
    }

    // 绘制所有图形
    public function drawAll() {
        echo "=== 绘制所有图形 ===\n";
        foreach ($this->shapes as $shape) {
            $shape->draw();
        }
    }

    // 移动所有图形
    public function moveAll($newX, $newY) {
        echo "\n=== 移动所有图形 ===\n";
        foreach ($this->shapes as $shape) {
            $shape->move($newX, $newY);
        }
    }

    // 缩放所有图形
    public function resizeAll($factor) {
        echo "\n=== 缩放所有图形 ===\n";
        foreach ($this->shapes as $shape) {
            $shape->resize($factor);
        }
    }

    // 计算总面积
    public function getTotalArea() {
        $totalArea = 0;
        foreach ($this->shapes as $shape) {
            $totalArea += $shape->getArea();
        }
        return $totalArea;
    }

    // 显示所有图形信息
    public function showShapeInfo() {
        echo "\n=== 图形信息 ===\n";
        foreach ($this->shapes as $index => $shape) {
            echo "图形 " . ($index + 1) . ":\n";
            echo "  面积: " . round($shape->getArea(), 2) . "\n";
            echo "  周长: " . round($shape->getPerimeter(), 2) . "\n";
        }
        echo "总面积: " . round($this->getTotalArea(), 2) . "\n";
    }
}

// 使用示例
$manager = new DrawingManager();

// 添加不同类型的图形
$manager->addShape(new Circle(5, 'red'));
$manager->addShape(new Rectangle(4, 6, 'blue'));
$manager->addShape(new Triangle(3, 4, 5, 'green'));
$manager->addShape(new Circle(3, 'yellow', 10, 20));

// 演示多态操作
$manager->drawAll();
$manager->moveAll(100, 100);
$manager->resizeAll(1.5);
$manager->showShapeInfo();
?>

多态的高级应用:插件系统

<?php
// 插件接口
interface PluginInterface {
    public function getName();
    public function getVersion();
    public function getDescription();
    public function execute($data);
    public function isEnabled();
    public function setEnabled($enabled);
}

// 基础插件类
abstract class BasePlugin implements PluginInterface {
    protected $name;
    protected $version;
    protected $description;
    protected $enabled = true;

    public function __construct($name, $version, $description) {
        $this->name = $name;
        $this->version = $version;
        $this->description = $description;
    }

    public function getName() {
        return $this->name;
    }

    public function getVersion() {
        return $this->version;
    }

    public function getDescription() {
        return $this->description;
    }

    public function isEnabled() {
        return $this->enabled;
    }

    public function setEnabled($enabled) {
        $this->enabled = $enabled;
    }

    abstract public function execute($data);
}

// 日志插件
class LoggerPlugin extends BasePlugin {
    private $logFile;

    public function __construct() {
        parent::__construct("日志插件", "1.0.0", "记录操作日志");
        $this->logFile = 'application.log';
    }

    public function execute($data) {
        if (!$this->isEnabled()) return;

        $timestamp = date('Y-m-d H:i:s');
        $logEntry = "[{$timestamp}] {$data}\n";
        file_put_contents($this->logFile, $logEntry, FILE_APPEND);
        echo "日志已记录:{$data}\n";
    }
}

// 缓存插件
class CachePlugin extends BasePlugin {
    private $cache = [];

    public function __construct() {
        parent::__construct("缓存插件", "2.1.0", "提供数据缓存功能");
    }

    public function execute($data) {
        if (!$this->isEnabled()) return $data;

        $key = md5(serialize($data));

        if (isset($this->cache[$key])) {
            echo "从缓存获取数据\n";
            return $this->cache[$key];
        }

        $processedData = $this->processData($data);
        $this->cache[$key] = $processedData;
        echo "数据已缓存\n";
        return $processedData;
    }

    private function processData($data) {
        // 模拟数据处理
        return "处理后的数据: " . $data;
    }

    public function clearCache() {
        $this->cache = [];
        echo "缓存已清空\n";
    }
}

// 安全检查插件
class SecurityPlugin extends BasePlugin {
    private $forbiddenWords = ['password', 'secret', 'token'];

    public function __construct() {
        parent::__construct("安全检查插件", "1.5.0", "检查敏感词汇");
    }

    public function execute($data) {
        if (!$this->isEnabled()) return $data;

        foreach ($this->forbiddenWords as $word) {
            if (stripos($data, $word) !== false) {
                echo "警告:检测到敏感词汇 '{$word}'\n";
                return str_ireplace($word, '***', $data);
            }
        }

        echo "安全检查通过\n";
        return $data;
    }
}

// 插件管理器
class PluginManager {
    private $plugins = [];

    // 注册插件
    public function registerPlugin(PluginInterface $plugin) {
        $this->plugins[] = $plugin;
        echo "插件已注册:{$plugin->getName()} v{$plugin->getVersion()}\n";
    }

    // 执行所有插件
    public function executePlugins($data) {
        echo "\n=== 执行插件处理 ===\n";
        $result = $data;

        foreach ($this->plugins as $plugin) {
            if ($plugin->isEnabled()) {
                echo "执行插件:{$plugin->getName()}\n";
                $result = $plugin->execute($result);
            }
        }

        return $result;
    }

    // 列出所有插件
    public function listPlugins() {
        echo "\n=== 插件列表 ===\n";
        foreach ($this->plugins as $plugin) {
            $status = $plugin->isEnabled() ? '启用' : '禁用';
            echo "名称: {$plugin->getName()}\n";
            echo "版本: {$plugin->getVersion()}\n";
            echo "描述: {$plugin->getDescription()}\n";
            echo "状态: {$status}\n";
            echo "---\n";
        }
    }

    // 启用/禁用插件
    public function togglePlugin($pluginName, $enabled) {
        foreach ($this->plugins as $plugin) {
            if ($plugin->getName() === $pluginName) {
                $plugin->setEnabled($enabled);
                $status = $enabled ? '启用' : '禁用';
                echo "插件 {$pluginName} 已{$status}\n";
                return true;
            }
        }
        echo "未找到插件: {$pluginName}\n";
        return false;
    }
}

// 使用示例
echo "=== 插件系统演示 ===\n";

$pluginManager = new PluginManager();

// 注册插件
$pluginManager->registerPlugin(new LoggerPlugin());
$pluginManager->registerPlugin(new CachePlugin());
$pluginManager->registerPlugin(new SecurityPlugin());

// 列出插件
$pluginManager->listPlugins();

// 执行插件
$data = "用户输入的敏感数据包含password信息";
$result = $pluginManager->executePlugins($data);
echo "\n最终结果: {$result}\n";

// 禁用安全插件
$pluginManager->togglePlugin("安全检查插件", false);
$result2 = $pluginManager->executePlugins("这个数据没有敏感词");
echo "\n禁用安全插件后的结果: {$result2}\n";
?>

多态的优势

1. 代码复用和扩展性

<?php
// 不使用多态的硬编码方式
function processPayment_V1($type, $amount) {
    if ($type === 'credit') {
        // 信用卡处理逻辑
        echo "处理信用卡支付\n";
    } elseif ($type === 'alipay') {
        // 支付宝处理逻辑
        echo "处理支付宝支付\n";
    } elseif ($type === 'wechat') {
        // 微信支付处理逻辑
        echo "处理微信支付\n";
    }
    // 添加新支付方式需要修改这个函数
}

// 使用多态的灵活方式
function processPayment_V2(PaymentInterface $payment, $amount) {
    $payment->processPayment($amount);
    // 添加新支付方式不需要修改这个函数
}
?>

2. 解耦和灵活性

多态减少了代码之间的耦合度,使系统更加灵活:

<?php
// 数据处理器接口
interface DataProcessorInterface {
    public function process($data);
}

// 处理器管理器
class ProcessorManager {
    private $processors = [];

    public function addProcessor(DataProcessorInterface $processor) {
        $this->processors[] = $processor;
    }

    public function processAll($data) {
        foreach ($this->processors as $processor) {
            $data = $processor->process($data);
        }
        return $data;
    }
}

// 可以随时添加新的处理器,而不需要修改管理器
?>

多态与类型检查

instanceof操作符

<?php
function handleAnimal(Animal $animal) {
    echo "处理动物: " . get_class($animal) . "\n";

    // 使用instanceof检查具体类型
    if ($animal instanceof Dog) {
        $animal->fetch();
    } elseif ($animal instanceof Cat) {
        $animal->climb();
    } else {
        // 处理其他类型的动物
        $animal->makeSound();
    }
}
?>

类型提示和返回类型

<?php
class ShapeFactory {
    public static function createShape(string $type): ShapeInterface {
        switch ($type) {
            case 'circle':
                return new Circle(5);
            case 'rectangle':
                return new Rectangle(4, 6);
            case 'triangle':
                return new Triangle(3, 4, 5);
            default:
                throw new Exception("未知的图形类型: $type");
        }
    }
}

// 使用
$shape = ShapeFactory::createShape('circle');
$shape->draw();
?>

多态的最佳实践

1. 遵循里氏替换原则

子类应该能够替换父类,并且程序的行为不会改变:

<?php
// 好的设计:子类完全符合父类的契约
class Rectangle {
    public function setWidth($width) { /* ... */ }
    public function setHeight($height) { /* ... */ }
    public function getArea() { /* ... */ }
}

class Square extends Rectangle {
    // 正方形需要同时设置宽和高
    public function setWidth($width) {
        parent::setWidth($width);
        parent::setHeight($width);
    }

    public function setHeight($height) {
        parent::setWidth($height);
        parent::setHeight($height);
    }
}

// 这里Square不能完全替代Rectangle,因为行为不同
// 更好的做法是使用共同接口而不是继承
?>

2. 优先使用接口而不是具体类

<?php
// 好的做法:依赖接口
class ReportGenerator {
    public function generate(DataExporterInterface $exporter) {
        $data = $this->collectData();
        return $exporter->export($data);
    }
}

// 而不是依赖具体类
class ReportGenerator_Bad {
    public function generate(PDFExporter $exporter) {  // 限制了扩展性
        $data = $this->collectData();
        return $exporter->export($data);
    }
}
?>

3. 避免过度使用instanceof

过多的类型检查可能表明设计有问题:

<?php
// 避免:过多的类型检查
function processShape(Shape $shape) {
    if ($shape instanceof Circle) {
        // 处理圆形
    } elseif ($shape instanceof Rectangle) {
        // 处理矩形
    } elseif ($shape instanceof Triangle) {
        // 处理三角形
    }
}

// 更好:在子类中实现特定行为
abstract class Shape {
    abstract public function process();
}

class Circle extends Shape {
    public function process() {
        // 圆形特有的处理逻辑
    }
}
?>

通过本节的学习,你应该掌握了多态的概念、实现方式和应用场景。多态是面向对象编程的重要特性,它让代码更加灵活、可扩展和易于维护。在实际开发中,合理使用多态可以大大提高代码的质量和可维护性。