桥接模式
外观
目录
桥接模式在代码经常因为实现和使用方法的变化而需要修改时非常有用。在你的应用程序中,你应该有提供者类和客户类
|
|
... |
|
◊— |
| |||||||||||||||||
... | ||||||||||||||||||||||
|
|
... |
|
每个客户类都可以与每个提供者类交互。但是,如果实现发生变化,提供者接口的方法签名可能会发生变化,并且所有客户类都必须更改。同样,如果客户类需要一个新的接口,我们需要重写所有提供者。解决办法是添加一个桥接,也就是一个由客户调用的类,它包含对提供者的引用,并将客户调用转发给提供者。
|
|
... |
|
◊— |
|
◊— |
| ||||||||||||||||||||
... | |||||||||||||||||||||||||||
|
|
... |
|
将来,这两个接口(客户端/桥接和桥接/提供者)可能会独立更改,桥接可能会对调用顺序进行转码。
示例
很难在库中找到示例,因为这种模式是为多功能规范而设计的,库在两个版本之间不会不断更改。
成本
这种模式的成本与适配器模式相同。它可以在设计时计划,但决定添加它的最佳方式是经验反馈。当你短时间内频繁地更改接口时,就可以实现它。
创建
它的实现很简单,但可能很昂贵。它取决于接口的复杂性。方法越多,成本就越高。
维护
如果你始终以相同的方式更新客户端/桥接接口和桥接/提供者接口,那么它比不实现设计模式更昂贵。
移除
这种模式很容易移除,因为自动重构操作可以轻松地移除它的存在。
建议
- 在桥接类的名称中添加“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.