学习目标
- 掌握桥接模式概念、优缺点以及实现过程
- 用代码实现桥接模式
桥接模式(Bridge Pattern)
概念
将抽象与实现分离,使它们可以独立变化。也就是在抽象类和具体实现之间建立一个桥梁,使得它们可以各自演化而互不影响。
优点
- 可扩展性。抽象和实现部分可以独立扩展,提高了系统的可扩展性。
- 灵活性。抽象和实现部分可以在运行时绑定,增强了系统的灵活性。
- 可重用性。实现部分可以在不同的抽象下重用。
缺点
- 复杂性。由于抽象和实现部分之间产生一个间接层,这增加了系统的理解与设计难度。
- 要求正确识别出系统中两个独立变化的维度,这并不总是很容易。
适用场景
- 一个类存在两个独立变化的维度,且这两个维度都需要扩展时。
- 不希望因为一个维度的变化而影响到另一个维度。
- 通过对多个维度的抽象来实现“可插拔”的类或对象。这可以通过实现不同的接口和继承来实现。
举个栗子
- 不同的操作系统和不同的 GUI 库(抽象和具体实现)。
- 不同数据库和不同的数据访问接口。
- 不同的消息协议和不同的消息实现。
模拟实现过程
- 定义一个接口/抽象类,以及继承者类需要实现的公共方法
- 定义一个抽象类,构造函数引入 1 中接口/抽象类的具体实现,并且定义与之交互的公共方法
- 实例化一个类,引入 1 中的接口,并实现其公共方法
- 继承 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
项目地址
总结
桥接模式可以提高系统的灵活性和可扩展性,减少类之间的依赖关系,使得系统更易于维护和扩展。它将抽象和实现的变化隔离开来,使得系统更具适应性和可配置性。