跳至内容

桥接模式

25% developed
来自维基教科书,自由的教科书

适配器模式 计算机科学设计模式
桥接模式
建造者模式

桥接模式在代码经常因为实现和使用方法的变化而需要修改时非常有用。在你的应用程序中,你应该有提供者类和客户类

客户1
- 提供者: 提供者
 
客户2
- 提供者: 提供者
...
客户N
- 提供者: 提供者
◊—
提供者
+doProcess()
...
提供者1
+doProcess()
提供者2
+doProcess()
...
提供者N
+doProcess()

每个客户类都可以与每个提供者类交互。但是,如果实现发生变化,提供者接口的方法签名可能会发生变化,并且所有客户类都必须更改。同样,如果客户类需要一个新的接口,我们需要重写所有提供者。解决办法是添加一个桥接,也就是一个由客户调用的类,它包含对提供者的引用,并将客户调用转发给提供者。

客户1
- 桥接: 桥接
 
客户2
- 桥接: 桥接
...
客户N
- 桥接: 桥接
◊—
桥接模式
- 提供者: 提供者
+doProcessForClient()
◊—
提供者
+doProcess()
...
提供者1
+doProcess()
提供者2
+doProcess()
...
提供者N
+doProcess()

将来,这两个接口(客户端/桥接和桥接/提供者)可能会独立更改,桥接可能会对调用顺序进行转码。

示例

很难在库中找到示例,因为这种模式是为多功能规范而设计的,库在两个版本之间不会不断更改。

成本

这种模式的成本与适配器模式相同。它可以在设计时计划,但决定添加它的最佳方式是经验反馈。当你短时间内频繁地更改接口时,就可以实现它。

创建

它的实现很简单,但可能很昂贵。它取决于接口的复杂性。方法越多,成本就越高。

维护

如果你始终以相同的方式更新客户端/桥接接口和桥接/提供者接口,那么它比不实现设计模式更昂贵。

移除

这种模式很容易移除,因为自动重构操作可以轻松地移除它的存在。

建议

  • 在桥接类的名称中添加“bridge”一词,以向其他开发人员表明使用该模式。

实现

Kotlin 实现
/** "Implementor" */
fun interface MusicPlayer {
    fun play(song: String): String
}

/** "ConcreteImplementor" 1/4 */
val defaultPlayer = MusicPlayer{
    "Reproducing $it in ${MusicFormat.NONE}"
}

/** "ConcreteImplementor" 2/4 */
val mp3Player = MusicPlayer{
    "Reproducing $it in ${MusicFormat.MP3}"
}

/** "ConcreteImplementor" 3/4 */
val mp4Player = MusicPlayer{
    "Reproducing $it in ${MusicFormat.MP4}"
}

/** "ConcreteImplementor" 4/4 */
val vlcPlayer = MusicPlayer{
    "Reproducing \"$it\" in ${MusicFormat.VLC}"
}

/** "Abstraction" */
abstract class MusicPlayerUI {
    var musicPlayer : MusicPlayer = defaultPlayer
    abstract fun playMusic(song: String, musicFormat: MusicFormat)
}

 /** "Refined Abstraction" */
class MyMusicPlayerUI : MusicPlayerUI() {
    override fun playMusic(song: String, musicFormat: MusicFormat) {
        musicPlayer = when(musicFormat) {
            MusicFormat.NONE -> defaultPlayer
            MusicFormat.MP3 -> mp3Player
            MusicFormat.MP4 -> mp4Player
            MusicFormat.VLC -> vlcPlayer
        }
        println(musicPlayer.play(song))
    }

}

enum class MusicFormat{
    NONE,MP3,MP4,VLC
}

 /** "Client" */
object BridgePattern {
    @JvmStatic
    fun main(args: Array<String>) {
        val musicPlayer = MyMusicPlayerUI()
        musicPlayer.playMusic("The best song", MusicFormat.MP4)
    }
}
Java 实现

以下 Java (SE 6) 程序说明了桥接模式。

/**
 * Implementor
 */
interface DrawingAPI {
    public void drawCircle(double x, double y, double radius);
}
/**
 * ConcreteImplementor  1/2
 */
class DrawingAPI1 implements DrawingAPI {
   public void drawCircle(double x, double y, double radius) {
        System.out.printf("API1.circle at %f:%f radius %f\n", x, y, radius);
   }
}
/**
 * ConcreteImplementor 2/2
 */
class DrawingAPI2 implements DrawingAPI {
   public void drawCircle(double x, double y, double radius) {
        System.out.printf("API2.circle at %f:%f radius %f\n", x, y, radius);
   }
}
/**
 * Abstraction
 */
abstract class Shape {
   protected DrawingAPI drawingAPI;

   protected Shape(DrawingAPI drawingAPI) {
      this.drawingAPI = drawingAPI;
   }

   public abstract void draw();                             // low-level
   public abstract void resizeByPercentage(double pct);     // high-level
}
/**
 * Refined Abstraction
 */
class CircleShape extends Shape {
   private double x, y, radius;
   public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI) {
      super(drawingAPI);
      this.x = x;
      this.y = y;
      this.radius = radius;
   }

   // low-level i.e. Implementation specific
   public void draw() {
        drawingAPI.drawCircle(x, y, radius);
   }

   // high-level i.e. Abstraction specific
   public void resizeByPercentage(double pct) {
        radius *= pct;
   }
}
/**
 * Client
 */
class BridgePattern {
   public static void main(String[] args) {
       Shape[] shapes = new Shape[] {
           new CircleShape(1, 2, 3, new DrawingAPI1()),
           new CircleShape(5, 7, 11, new DrawingAPI2()),
       };

       for (Shape shape : shapes) {
           shape.resizeByPercentage(2.5);
           shape.draw();
       }
   }
}

它将输出

API1.circle at 1.000000:2.000000 radius 7.5000000
API2.circle at 5.000000:7.000000 radius 27.500000
PHP 实现
interface DrawingAPI {
    function drawCircle($dX, $dY, $dRadius);
}

class DrawingAPI1 implements DrawingAPI {

    public function drawCircle($dX, $dY, $dRadius) {
        echo "API1.circle at ".$dX.":".$dY." radius ".$dRadius."<br/>";
    }
}

class DrawingAPI2 implements DrawingAPI {

    public function drawCircle($dX, $dY, $dRadius) {
        echo "API2.circle at ".$dX.":".$dY." radius ".$dRadius."<br/>";
    }
}

abstract class Shape {

    protected $oDrawingAPI;

    public abstract function draw();
    public abstract function resizeByPercentage($dPct);

    protected function __construct(DrawingAPI $oDrawingAPI) {
        $this->oDrawingAPI = $oDrawingAPI;
    }
}

class CircleShape extends Shape {

    private $dX;
    private $dY;
    private $dRadius;

    public function __construct(
            $dX, $dY,
            $dRadius,
            DrawingAPI $oDrawingAPI
    ) {
        parent::__construct($oDrawingAPI);
        $this->dX = $dX;
        $this->dY = $dY;
        $this->dRadius = $dRadius;
    }

    public function draw() {
        $this->oDrawingAPI->drawCircle(
                $this->dX,
                $this->dY,
                $this->dRadius
        );
    }

    public function resizeByPercentage($dPct) {
        $this->dRadius *= $dPct;
    }
}

class Tester {

    public static function main()  {
        $aShapes = array(
            new CircleShape(1, 3, 7,  new DrawingAPI1()),
            new CircleShape(5, 7, 11, new DrawingAPI2()),
        );

        foreach ($aShapes as $shapes) {
            $shapes->resizeByPercentage(2.5);
            $shapes->draw();
        }
    }
}

Tester::main();

输出

   API1.circle at 1:3 radius 17.5
   API2.circle at 5:7 radius 27.5
C# 实现

C#

以下 C# 程序说明了上面给出的“形状”示例,并将输出

API1.circle at 1:2 radius 7.5
API2.circle at 5:7 radius 27.5
 using System;
 
 /** "Implementor" */
 interface IDrawingAPI {
    void DrawCircle(double x, double y, double radius);
 }
 
 /** "ConcreteImplementor" 1/2 */
 class DrawingAPI1 : IDrawingAPI {
    public void DrawCircle(double x, double y, double radius)
    {
        System.Console.WriteLine("API1.circle at {0}:{1} radius {2}", x, y, radius);
    }
 }
 
 /** "ConcreteImplementor" 2/2 */
 class DrawingAPI2 : IDrawingAPI
 {
    public void DrawCircle(double x, double y, double radius)
    {
        System.Console.WriteLine("API2.circle at {0}:{1} radius {2}", x, y, radius);
    }
 }
 
 /** "Abstraction" */
 interface IShape {
    void Draw();                             // low-level (i.e. Implementation-specific)
    void ResizeByPercentage(double pct);     // high-level (i.e. Abstraction-specific)
 }
 
 /** "Refined Abstraction" */
 class CircleShape : IShape {
    private double x, y, radius;
    private IDrawingAPI drawingAPI;
    public CircleShape(double x, double y, double radius, IDrawingAPI drawingAPI)
    {
        this.x = x;  this.y = y;  this.radius = radius;
        this.drawingAPI = drawingAPI;
    }
    // low-level (i.e. Implementation-specific)
    public void Draw() { drawingAPI.DrawCircle(x, y, radius); }
    // high-level (i.e. Abstraction-specific)
    public void ResizeByPercentage(double pct) { radius *= pct; }
 }
 
 /** "Client" */
 class BridgePattern {
    public static void Main(string[] args) {
        IShape[] shapes = new IShape[2];
        shapes[0] = new CircleShape(1, 2, 3, new DrawingAPI1());
        shapes[1] = new CircleShape(5, 7, 11, new DrawingAPI2());
 
        foreach (IShape shape in shapes) {
            shape.ResizeByPercentage(2.5);
            shape.Draw();
        }
    }
 }

C# 使用泛型

以下 C# 程序说明了上面给出的“形状”示例,并将输出

API1.circle at 1:2 radius 7.5
API2.circle at 5:7 radius 27.5
 using System;
 
 /** "Implementor" */
 interface IDrawingAPI {
    void DrawCircle(double x, double y, double radius);
 }
 
 /** "ConcreteImplementor" 1/2 */
 struct DrawingAPI1 : IDrawingAPI {
    public void DrawCircle(double x, double y, double radius)
    {
        System.Console.WriteLine("API1.circle at {0}:{1} radius {2}", x, y, radius);
    }
 }
 
 /** "ConcreteImplementor" 2/2 */
 struct DrawingAPI2 : IDrawingAPI
 {
    public void DrawCircle(double x, double y, double radius)
    {
        System.Console.WriteLine("API2.circle at {0}:{1} radius {2}", x, y, radius);
    }
 }
 
 /** "Abstraction" */
 interface IShape {
    void Draw();                             // low-level (i.e. Implementation-specific)
    void ResizeByPercentage(double pct);     // high-level (i.e. Abstraction-specific)
 }
 
 /** "Refined Abstraction" */
 class CircleShape<T> : IShape
    where T : struct, IDrawingAPI
 {
    private double x, y, radius;
    private IDrawingAPI drawingAPI = new T();
    public CircleShape(double x, double y, double radius)
    {
        this.x = x;  this.y = y;  this.radius = radius;
    }
    // low-level (i.e. Implementation-specific)
    public void Draw() { drawingAPI.DrawCircle(x, y, radius); }
    // high-level (i.e. Abstraction-specific)
    public void ResizeByPercentage(double pct) { radius *= pct; }
 }
 
 /** "Client" */
 class BridgePattern {
    public static void Main(string[] args) {
        IShape[] shapes = new IShape[2];
        shapes[0] = new CircleShape<DrawingAPI1>(1, 2, 3);
        shapes[1] = new CircleShape<DrawingAPI2>(5, 7, 11);
 
        foreach (IShape shape in shapes) {
            shape.ResizeByPercentage(2.5);
            shape.Draw();
        }
    }
 }
Python 实现

以下 Python 程序说明了上面给出的“形状”示例,并将输出

API1.circle at 1:2 7.5
API2.circle at 5:7 27.5
# Implementor
class DrawingAPI:
    def drawCircle(x, y, radius):
        pass


# ConcreteImplementor 1/2
class DrawingAPI1(DrawingAPI):
    def drawCircle(self, x, y, radius):
        print("API1.circle at %f:%f radius %f" % (x, y, radius))


# ConcreteImplementor 2/2
class DrawingAPI2(DrawingAPI):
    def drawCircle(self, x, y, radius):
        print("API2.circle at %f:%f radius %f" % (x, y, radius))


# Abstraction
class Shape:
    # low-level
    def draw(self):
        pass

    # high-level
    def resizeByPercentage(self, pct):
        pass


# Refined Abstraction
class CircleShape(Shape):
    def __init__(self, x, y, radius, drawingAPI):
        self.__x = x
        self.__y = y
        self.__radius = radius
        self.__drawingAPI = drawingAPI

    # low-level i.e. Implementation specific
    def draw(self):
        self.__drawingAPI.drawCircle(self.__x, self.__y, self.__radius)

    # high-level i.e. Abstraction specific
    def resizeByPercentage(self, pct):
        self.__radius *= pct


def main():
    shapes = [
        CircleShape(1, 2, 3, DrawingAPI1()),
        CircleShape(5, 7, 11, DrawingAPI2())
    ]

    for shape in shapes:
        shape.resizeByPercentage(2.5)
        shape.draw()


if __name__ == "__main__":
    main()
Ruby 实现

一个在 Ruby 中的示例。

class Abstraction
  def initialize(implementor)
    @implementor = implementor
  end

  def operation
    raise 'Implementor object does not respond to the operation method' unless @implementor.respond_to?(:operation)
    @implementor.operation
  end
end

class RefinedAbstraction < Abstraction
  def operation
    puts 'Starting operation... '
    super
  end
end

class Implementor
  def operation
    puts 'Doing necessary stuff'
  end
end

class ConcreteImplementorA < Implementor
  def operation
    super
    puts 'Doing additional stuff'
  end
end

class ConcreteImplementorB < Implementor
  def operation
    super
    puts 'Doing other additional stuff'
  end
end

normal_with_a = Abstraction.new(ConcreteImplementorA.new)
normal_with_a.operation
# Doing necessary stuff
# Doing additional stuff

normal_with_b = Abstraction.new(ConcreteImplementorB.new)
normal_with_b.operation
# Doing necessary stuff
# Doing other additional stuff

refined_with_a = RefinedAbstraction.new(ConcreteImplementorA.new)
refined_with_a.operation
# Starting operation...
# Doing necessary stuff
# Doing additional stuff

refined_with_b = RefinedAbstraction.new(ConcreteImplementorB.new)
refined_with_b.operation
# Starting operation...
# Doing necessary stuff
# Doing other additional stuff
Scala 实现

一个 Scala 实现的 Java 绘图示例,具有相同的输出。

  /** "Implementor" */
  trait DrawingAPI {
    def drawCircle(x:Double, y:Double, radius:Double)
  }
 
  /** "ConcreteImplementor" 1/2 */
  class DrawingAPI1 extends DrawingAPI {
    def drawCircle(x:Double, y:Double, radius:Double) {
      printf("API1.circle at %f:%f radius %f\n", x, y, radius)
    }
  }
 
  /** "ConcreteImplementor" 2/2 */
  class DrawingAPI2 extends DrawingAPI {
    def drawCircle(x:Double, y:Double, radius:Double) {
      printf("API2.circle at %f:%f radius %f\n", x, y, radius)
    }
  }
 
  /** "Abstraction" */
  trait Shape {
     def draw()                             // low-level
     def resizeByPercentage(pct:Double)     // high-level
  }
 
  /** "Refined Abstraction" */
  class CircleShape(var x:Double, var y:Double,
    var radius:Double, val drawingAPI:DrawingAPI) extends Shape {
   
    // low-level i.e. Implementation specific
    def draw() = drawingAPI.drawCircle(x, y, radius)
   
    // high-level i.e. Abstraction specific
    def resizeByPercentage(pct:Double) = radius *= pct
  }
 
  /** "Client" */
  val shapes = List(
    new CircleShape(1, 2, 3, new DrawingAPI1),
    new CircleShape(5, 7, 11, new DrawingAPI2)
  )
 
  shapes foreach { shape =>
    shape.resizeByPercentage(2.5)
    shape.draw()
  }
D 实现

一个在 D 中的示例。

import std.stdio;

/** "Implementor" */
interface DrawingAPI {
    void drawCircle(double x, double y, double radius);
}

/** "ConcreteImplementor" 1/2 */
class DrawingAPI1: DrawingAPI {
    void drawCircle(double x, double y, double radius) {
        writefln("\nAPI1.circle at %f:%f radius %f", x, y, radius);
    }
}

/** "ConcreteImplementor" 2/2 */
class DrawingAPI2: DrawingAPI {
    void drawCircle(double x, double y, double radius) {
        writefln("\nAPI2.circle at %f:%f radius %f", x, y, radius);
    }
}

/** "Abstraction" */
interface Shape {
    void draw(); // low-level
    void resizeByPercentage(double pct); // high-level
}

/** "Refined Abstraction" */
class CircleShape: Shape {
    this(double x, double y, double radius, DrawingAPI drawingAPI) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.drawingAPI = drawingAPI;
    }

    // low-level i.e. Implementation specific
    void draw() {
        drawingAPI.drawCircle(x, y, radius);
    }
    // high-level i.e. Abstraction specific
    void resizeByPercentage(double pct) {
        radius *= pct;
    }
private:
    double x, y, radius;
    DrawingAPI drawingAPI;
}

int main(string[] argv) {
    auto api1 = new DrawingAPI1();
    auto api2 = new DrawingAPI2();

    auto c1 = new CircleShape(1, 2, 3, api1);
    auto c2 = new CircleShape(5, 7, 11, api2);

    Shape[4] shapes;
    shapes[0] = c1;
    shapes[1] = c2;

    shapes[0].resizeByPercentage(2.5);
    shapes[0].draw();
    shapes[1].resizeByPercentage(2.5);
    shapes[1].draw();

    return 0;
}
Perl 实现

这个在 Perl 中的示例使用了 MooseX::Declare 模块。

# Implementor
role Drawing::API {
    requires 'draw_circle';
}

# Concrete Implementor 1
class Drawing::API::1 with Drawing::API {
    method draw_circle(Num $x, Num $y, Num $r) {
        printf "API1.circle at %f:%f radius %f\n", $x, $y, $r;
    }
}

# Concrete Implementor 2
class Drawing::API::2 with Drawing::API {
    method draw_circle(Num $x, Num $y, Num $r) {
        printf "API2.circle at %f:%f radius %f\n", $x, $y, $r;
    }
}

# Abstraction
role Shape {
    requires qw( draw resize );
}

# Refined Abstraction
class Shape::Circle with Shape {
    has $_  => ( is => 'rw', isa  => 'Any' ) for qw( x y r );
    has api => ( is => 'ro', does => 'Drawing::API' );

    method draw() {
        $self->api->draw_circle( $self->x, $self->y, $self->r );
    }

    method resize(Num $percentage) {
        $self->{r} *= $percentage;
    }
}

my @shapes = (
    Shape::Circle->new( x=>1, y=>2, r=>3,  api => Drawing::API::1->new ),
    Shape::Circle->new( x=>5, y=>7, r=>11, api => Drawing::API::2->new ),
)

$_->resize( 2.5 ) and $_->draw for @shapes;
Delphi 实现

以下 Delphi 程序说明了上面给出的“形状”示例,并将输出

API1.circle at 1:2 7.5
API2.circle at 5:7 27.5
program Bridge;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type

  ///implementator
  TDrawingAPI = class abstract
    procedure DrawCircle(x, y, radius: double); virtual; abstract;
  end;

  //ConcreteImplementator 1
  TDrawingAPI1 = class(TDrawingAPI)
    procedure DrawCircle(x, y, radius: double); override;
  end;

 //ConcreteImplementator 2
  TDrawingAPI2 = class(TDrawingAPI)
    procedure DrawCircle(x, y, radius: double);override;
  end;

  //Abstraction
  TShape = class abstract
    procedure Draw();virtual; abstract;// low-level (i.e. Implementation-specific)
    procedure ResizeByPercentage(pct: double);virtual; abstract;// high-level (i.e. Abstraction-specific)
  end;

  //Refined Abstraction
  TCircleShape = class(TShape)
    strict private
      x, y, radius: double;
      drawingAPI: TDrawingAPI;
    public
      constructor Create(x, y, radius: double; drawingAPI: TDrawingAPI);
      procedure Draw;override;
      procedure ResizeByPercentage(pct: double);override;
  end;

{ TDeawingAPI1 }

procedure TDrawingAPI1.DrawCircle(x, y, radius: double);
begin
  WriteLn('API1.circle at '+FloatToStr(x)+' : '+FloatToStr(y)+' radius '+FloatToStr(radius));
end;

{ TDeawingAPI }

procedure TDrawingAPI2.DrawCircle(x, y, radius: double);
begin
  WriteLn('API2.circle at '+FloatToStr(x)+' : '+FloatToStr(y)+' radius '+FloatToStr(radius));
end;

{ TCircleShape }

constructor TCircleShape.Create(x, y, radius: double; drawingAPI: TDrawingAPI);
begin
  self.x := x;
  self.y := y;
  self.radius := radius;
  self.drawingAPI := drawingAPI;
end;

procedure TCircleShape.Draw;
begin
  drawingAPI.DrawCircle(x, y, radius);
end;

procedure TCircleShape.ResizeByPercentage(pct: double);
begin
  radius := radius * pct;
end;

var shapes: array of TShape;
    shape: TShape;
begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
    SetLength(shapes, 2);
    shapes[0] := TCircleShape.Create(1, 2, 3, TDrawingAPI1.Create);
    shapes[1] := TCircleShape.Create(5, 7, 11, TDrawingAPI2.Create);

    for shape in shapes do
    begin
       shape.ResizeByPercentage(2.5);
       shape.Draw;
    end;

    WriteLn(#13#10+'Press any key to continue..');
    ReadLn;

    shapes[0].Free;
    shapes[1].Free;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.


Clipboard

待办事项
添加更多插图。


适配器模式 计算机科学设计模式
桥接模式
建造者模式


您对此页面有疑问吗?
在此提问


在此书中创建一个新页面


华夏公益教科书