设计模式解密:桥接模式的终极指南(PHP/Go双实现)
一、什么是桥接模式?
桥接模式(Bridge Pattern) 是一种结构型设计模式,用于将抽象部分与实现部分分离,使它们可以独立变化。桥接模式的核心思想是通过组合而非继承来解耦抽象与实现,从而提高系统的灵活性和可扩展性。
核心角色:
抽象部分(Abstraction):定义高层控制逻辑
扩展抽象(Refined Abstraction):扩展抽象部分的功能
实现部分(Implementor):定义底层操作的接口
具体实现(Concrete Implementor):实现底层操作
二、适用场景
✅ 需要将抽象与实现解耦
✅ 需要在运行时切换实现
✅ 需要避免多层继承
✅ 需要在多个维度上扩展类
三、PHP实现方案
1. 基础实现
interface Renderer {
public function render(string $shape): string;
}
class HtmlRenderer implements Renderer {
public function render(string $shape): string {
return "HTML: Rendering $shape";
}
}
class PdfRenderer implements Renderer {
public function render(string $shape): string {
return "PDF: Rendering $shape";
}
}
abstract class Shape {
protected $renderer;
public function __construct(Renderer $renderer) {
$this->renderer = $renderer;
}
abstract public function draw(): string;
}
class Circle extends Shape {
public function draw(): string {
return $this->renderer->render("Circle");
}
}
class Square extends Shape {
public function draw(): string {
return $this->renderer->render("Square");
}
}
// 使用示例
$htmlRenderer = new HtmlRenderer();
$pdfRenderer = new PdfRenderer();
$circle = new Circle($htmlRenderer);
echo $circle->draw(); // 输出:HTML: Rendering Circle
$square = new Square($pdfRenderer);
echo $square->draw(); // 输出:PDF: Rendering Square
2. 进阶实现(多维度扩展)
interface Color {
public function fill(): string;
}
class Red implements Color {
public function fill(): string {
return "Red";
}
}
class Blue implements Color {
public function fill(): string {
return "Blue";
}
}
abstract class Shape {
protected $renderer;
protected $color;
public function __construct(Renderer $renderer, Color $color) {
$this->renderer = $renderer;
$this->color = $color;
}
abstract public function draw(): string;
}
class Circle extends Shape {
public function draw(): string {
return $this->renderer->render("Circle with " . $this->color->fill());
}
}
// 使用示例
$htmlRenderer = new HtmlRenderer();
$red = new Red();
$circle = new Circle($htmlRenderer, $red);
echo $circle->draw(); // 输出:HTML: Rendering Circle with Red
四、Go实现方案
1. 基础实现
package main
import "fmt"
type Renderer interface {
Render(shape string) string
}
type HtmlRenderer struct{}
func (h HtmlRenderer) Render(shape string) string {
return fmt.Sprintf("HTML: Rendering %s", shape)
}
type PdfRenderer struct{}
func (p PdfRenderer) Render(shape string) string {
return fmt.Sprintf("PDF: Rendering %s", shape)
}
type Shape struct {
renderer Renderer
}
func NewShape(renderer Renderer) *Shape {
return &Shape{renderer: renderer}
}
type Circle struct {
*Shape
}
func NewCircle(renderer Renderer) *Circle {
return &Circle{Shape: NewShape(renderer)}
}
func (c *Circle) Draw() string {
return c.renderer.Render("Circle")
}
type Square struct {
*Shape
}
func NewSquare(renderer Renderer) *Square {
return &Square{Shape: NewShape(renderer)}
}
func (s *Square) Draw() string {
return s.renderer.Render("Square")
}
// 使用示例
func main() {
htmlRenderer := HtmlRenderer{}
pdfRenderer := PdfRenderer{}
circle := NewCircle(htmlRenderer)
fmt.Println(circle.Draw()) // 输出:HTML: Rendering Circle
square := NewSquare(pdfRenderer)
fmt.Println(square.Draw()) // 输出:PDF: Rendering Square
}
2. 进阶实现(多维度扩展)
package main
import "fmt"
type Color interface {
Fill() string
}
type Red struct{}
func (r Red) Fill() string {
return "Red"
}
type Blue struct{}
func (b Blue) Fill() string {
return "Blue"
}
type Shape struct {
renderer Renderer
color Color
}
func NewShape(renderer Renderer, color Color) *Shape {
return &Shape{renderer: renderer, color: color}
}
type Circle struct {
*Shape
}
func NewCircle(renderer Renderer, color Color) *Circle {
return &Circle{Shape: NewShape(renderer, color)}
}
func (c *Circle) Draw() string {
return c.renderer.Render("Circle with " + c.color.Fill())
}
// 使用示例
func main() {
htmlRenderer := HtmlRenderer{}
red := Red{}
circle := NewCircle(htmlRenderer, red)
fmt.Println(circle.Draw()) // 输出:HTML: Rendering Circle with Red
}
五、关键实现差异对比
六、模式优缺点分析
👍 优点:
解耦抽象与实现:抽象部分和实现部分可以独立变化
提高扩展性:支持多维度扩展
减少继承层次:避免多层继承带来的复杂性
👎 缺点:
增加复杂度:引入额外的类和接口
设计难度高:需要合理划分抽象与实现
七、实际应用案例
1. 图形绘制系统
// PHP示例
$vectorRenderer = new VectorRenderer();
$rasterRenderer = new RasterRenderer();
$redCircle = new Circle($vectorRenderer, new Red());
$blueSquare = new Square($rasterRenderer, new Blue());
echo $redCircle->draw(); // 输出:Vector: Rendering Circle with Red
echo $blueSquare->draw(); // 输出:Raster: Rendering Square with Blue
2. 日志系统
// Go示例
type Logger interface {
Log(message string)
}
type FileLogger struct{}
func (f FileLogger) Log(message string) {
fmt.Println("Log to file:", message)
}
type ConsoleLogger struct{}
func (c ConsoleLogger) Log(message string) {
fmt.Println("Log to console:", message)
}
type LogLevel int
const (
Info LogLevel = iota
Error
)
type LogHandler struct {
logger Logger
level LogLevel
}
func NewLogHandler(logger Logger, level LogLevel) *LogHandler {
return &LogHandler{logger: logger, level: level}
}
func (l *LogHandler) Handle(message string) {
if l.level == Info {
l.logger.Log("[INFO] " + message)
} else {
l.logger.Log("[ERROR] " + message)
}
}
// 使用示例
func main() {
fileLogger := FileLogger{}
consoleLogger := ConsoleLogger{}
infoHandler := NewLogHandler(fileLogger, Info)
errorHandler := NewLogHandler(consoleLogger, Error)
infoHandler.Handle("System started") // 输出:Log to file: [INFO] System started
errorHandler.Handle("System crashed") // 输出:Log to console: [ERROR] System crashed
}
3. 消息通知系统
// PHP示例
$emailNotifier = new EmailNotifier();
$smsNotifier = new SmsNotifier();
$urgentMessage = new UrgentMessage($emailNotifier);
$normalMessage = new NormalMessage($smsNotifier);
echo $urgentMessage->send("System alert!"); // 输出:Email: Sending urgent message - System alert!
echo $normalMessage->send("Daily report"); // 输出:SMS: Sending normal message - Daily report
八、与适配器模式的区别
九、总结
桥接模式是解耦抽象与实现的利器,通过组合而非继承,它提供了极大的灵活性和扩展性。无论是PHP的构造函数注入还是Go的结构体嵌入,桥接模式都能显著提升代码的可维护性和可扩展性。
在下一篇文章中,我们将探讨 组合模式 及其在树形结构中的应用。敬请期待!
下一篇预告:设计模式系列(八)——组合模式:树形结构的艺术
License:
CC BY 4.0