重学设计模式——桥接模式

179 阅读2分钟

学习目标

  1. 掌握桥接模式概念、优缺点以及实现过程
  2. 用代码实现桥接模式

桥接模式(Bridge Pattern)

概念

将抽象与实现分离,使它们可以独立变化。也就是在抽象类和具体实现之间建立一个桥梁,使得它们可以各自演化而互不影响。

优点

  1. 可扩展性。抽象和实现部分可以独立扩展,提高了系统的可扩展性。
  2. 灵活性。抽象和实现部分可以在运行时绑定,增强了系统的灵活性。
  3. 可重用性。实现部分可以在不同的抽象下重用。

缺点

  1. 复杂性。由于抽象和实现部分之间产生一个间接层,这增加了系统的理解与设计难度。
  2. 要求正确识别出系统中两个独立变化的维度,这并不总是很容易。

适用场景

  1. 一个类存在两个独立变化的维度,且这两个维度都需要扩展时。
  2. 不希望因为一个维度的变化而影响到另一个维度。
  3. 通过对多个维度的抽象来实现“可插拔”的类或对象。这可以通过实现不同的接口和继承来实现。

举个栗子

  1. 不同的操作系统和不同的 GUI 库(抽象和具体实现)。
  2. 不同数据库和不同的数据访问接口。
  3. 不同的消息协议和不同的消息实现。

模拟实现过程

  1. 定义一个接口/抽象类,以及继承者类需要实现的公共方法
  2. 定义一个抽象类,构造函数引入 1 中接口/抽象类的具体实现,并且定义与之交互的公共方法
  3. 实例化一个类,引入 1 中的接口,并实现其公共方法
  4. 继承 2 中的抽象类,构造函数引入 3 中的具体类,并实现 2 中的抽象类方法,与 3 中引入的具体类做交互,达到具体类能随意搭配组合的目的

代码实现

Implementor.php

<?php

namespace Jmaat\DesignPatterns\Structural\Bridge;

/**
 * 实现部分的接口
 */
interface Implementor
{
    public function operationImpl();
}

Abstraction.php

<?php

namespace Jmaat\DesignPatterns\Structural\Bridge;

/**
 * 抽象部分
 */
abstract class Abstraction
{
    protected $implementor;

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

    /**
     * 执行操作
     * @return string
     */
    public function operation()
    {
        return $this->implementor->operationImpl();
    }
}

ConcreteImplementorA.php

<?php

namespace Jmaat\DesignPatterns\Structural\Bridge;

/**
 * 具体实现部分 A
 */
class ConcreteImplementorA implements Implementor
{
    public function operationImpl()
    {
        return "具体实现 A 的方法执行\n";
    }
}

ConcreteImplementorB.php

<?php

namespace Jmaat\DesignPatterns\Structural\Bridge;

/**
 * 具体实现部分 B
 */
class ConcreteImplementorB implements Implementor
{
    public function operationImpl()
    {
        return "具体实现 B 的方法执行\n";
    }
}

RefinedAbstractionA.php

<?php

namespace Jmaat\DesignPatterns\Structural\Bridge;

/**
 * 具体抽象部分A
 */
class RefinedAbstractionA extends Abstraction
{
    public function operation()
    {
        return "具体抽象部分 A 执行\n" . parent::operation();
    }
}

RefinedAbstractionB.php

<?php

namespace Jmaat\DesignPatterns\Structural\Bridge;

/**
 * 具体抽象部分A
 */
class RefinedAbstractionB extends Abstraction
{
    public function operation()
    {
        return "具体抽象部分 B 执行\n" . parent::operation();
    }
}

BridgeTest.php

<?php

namespace Jmaat\DesignPatterns\Structural\Bridge\tests;

use Jmaat\DesignPatterns\Structural\Bridge\ConcreteImplementorA;
use Jmaat\DesignPatterns\Structural\Bridge\ConcreteImplementorB;
use Jmaat\DesignPatterns\Structural\Bridge\RefinedAbstractionA;
use Jmaat\DesignPatterns\Structural\Bridge\RefinedAbstractionB;
use PHPUnit\Framework\TestCase;

class BridgeTest extends TestCase
{
    public function testBridge()
    {
        // 使用示例
        $implementorA new ConcreteImplementorA();
        $implementorB new ConcreteImplementorB();

        $abstractionA new RefinedAbstractionA($implementorA);
        echo $abstractionA->operation().PHP_EOL.'<------>'.PHP_EOL; // 输出: 具体抽象部分 A 执行 具体实现 A 的方法执行

        $abstractionA new RefinedAbstractionA($implementorB);
        echo $abstractionA->operation().PHP_EOL.'<------>'.PHP_EOL; // 输出: 具体抽象部分 A 执行 具体实现 A 的方法执行

        $abstractionB new RefinedAbstractionB($implementorA);
        echo $abstractionB->operation().PHP_EOL.'<------>'.PHP_EOL; // 输出: 具体抽象部分 B 执行 具体实现 B 的方法执行

        $abstractionB new RefinedAbstractionB($implementorB);
        echo $abstractionB->operation().PHP_EOL.'<------>'.PHP_EOL; // 输出: 具体抽象部分 B 执行 具体实现 B 的方法执行

        $this->assertTrue(true);
    }
}

单元测试

.\vendor\bin\phpunit .\src\Structural\Bridge\tests\BridgeTest

项目地址

gitee.com/jmaat/desig…

总结

桥接模式可以提高系统的灵活性和可扩展性,减少类之间的依赖关系,使得系统更易于维护和扩展。它将抽象和实现的变化隔离开来,使得系统更具适应性和可配置性。