Go和Java实现桥接模式
我们下面通过跨平台(Windows、Mac 和 Linux)播放不同格式的视频文件(mpeg、rmvb、avi 和 wmv)来说明桥接
模式的使用。
1、桥接模式
桥接是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽
象化和实现化之间的桥接结构,来实现二者的解耦。
这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类,这两种类型的类可被结构化改变而互
不影响。
桥接模式的目的是将抽象与实现分离,使它们可以独立地变化,该模式通过将一个对象的抽象部分与它的实现部分
分离,使它们可以独立地改变。它通过组合的方式,而不是继承的方式,将抽象和实现的部分连接起来。
-
意图:将抽象部分与实现部分分离,使它们都可以独立的变化。
-
主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。
-
何时使用:实现系统可能有多个角度分类,每一种角度都可能变化。
-
如何解决:把这种多角度分类分离出来,让它们独立变化,减少它们之间耦合。
-
关键代码:抽象类依赖实现类。
-
应用实例:1、猪八戒从天蓬元帅转世投胎到猪,转世投胎的机制将尘世划分为两个等级,即:灵魂和肉体,
前者相当于抽象化,后者相当于实现化。生灵通过功能的委派,调用肉体对象的功能,使得生灵可以动态地选
择。 2、墙上的开关,可以看到的开关是抽象的,不用管里面具体怎么实现的。
-
优点:1、抽象和实现的分离。 2、优秀的扩展能力。 3、实现细节对客户透明。
-
缺点:桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象
进行设计与编程。
-
使用场景:1、如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次
之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。 2、对于那些不希望使用继
承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。 3、一个类存在两个独立变化的
维度,且这两个维度都需要进行扩展。
-
注意事项:对于两个独立变化的维度,使用桥接模式再适合不过了。
-
以下是桥接模式的几个关键角色:
抽象(Abstraction):定义抽象接口,通常包含对实现接口的引用。
扩展抽象(Refined Abstraction):对抽象的扩展,可以是抽象类的子类或具体实现类。
实现(Implementor):定义实现接口,提供基本操作的接口。
具体实现(Concrete Implementor):实现实现接口的具体类。
-
适用性:
你不希望在抽象和它的实现部分之间有一个固定的绑定关系,例如这种情况可能是因为,在程序运行时刻实现
部分应可以进行选择或者切换。
类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充,这时 Bridge 模式使你可以对不同的抽象接
口和实现部分进行组合,并分别对它们进行扩充。
对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。
如果有许多类要生成,你必须将一个对象分解成两个部分。
设想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。
2、Go实现桥接模式
package bridge// ==========Video==========
type Video interface {Format()
}
package bridgeimport "fmt"// ==========Avi==========
type Avi struct {
}func (avi *Avi) Format() {fmt.Println("avi format!")
}
package bridgeimport "fmt"// ==========Mpeg==========
type Mpeg struct {
}func (mpeg *Mpeg) Format() {fmt.Println("mpeg format!")
}
package bridgeimport "fmt"// ==========Rmvb==========
type Rmvb struct {
}func (rmvb *Rmvb) Format() {fmt.Println("rmvb format!")
}
package bridgeimport "fmt"// ==========Wmv==========
type Wmv struct {
}func (wmv *Wmv) Format() {fmt.Println("wmv format!")
}
package bridge// ==========Platform==========
type Platform interface {Play()
}
package bridgeimport "fmt"// ==========Linux==========
type Linux struct {Video
}func (linux *Linux) Play() {fmt.Println("linux platform play:")linux.Video.Format()
}
package bridgeimport "fmt"// ==========Windows==========
type Windows struct {Video
}func (windows *Windows) Play() {fmt.Println("windows platform play:")windows.Video.Format()
}
package bridgeimport "fmt"// ==========Mac==========
type Mac struct {Video
}func (mac *Mac) Play() {fmt.Println("mac platform play:")mac.Video.Format()
}
package mainimport . "proj/bridge"func main() {// ==========Windows=======// ==========Mpeg==========winMpeg := &Windows{Video: &Mpeg{}}winMpeg.Play()// ==========Linux========// ==========Wmv==========linuxWmv := &Linux{Video: &Wmv{}}linuxWmv.Play()// ==========Mac==========// ==========Avi==========macAvi := &Mac{Video: &Avi{}}macAvi.Play()
}
# 输出
windows platform play:
mpeg format!
linux platform play:
wmv format!
mac platform play:
avi format!
3、Java实现桥接模式
package com.bridge;// ==========Video==========
public interface Video {void format();
}
package com.bridge;// ==========Avi==========
public class Avi implements Video{@Overridepublic void format() {System.out.println("avi format!");}
}
package com.bridge;// ==========Mpeg==========
public class Mpeg implements Video{@Overridepublic void format() {System.out.println("mpeg format!");}
}
package com.bridge;// ==========Rmvb==========
public class Rmvb implements Video{@Overridepublic void format() {System.out.println("rmvb format!");}
}
package com.bridge;// ==========Wmv==========
public class Wmv implements Video{@Overridepublic void format() {System.out.println("wmv format!");}
}
package com.bridge;// ==========Platform==========
public abstract class Platform {Video video;abstract void play();
}
package com.bridge;// ==========Linux==========
public class Linux extends Platform{public Linux(Video video){this.video = video;}@Overridepublic void play() {System.out.println("linux platform play:");this.video.format();}
}
package com.bridge;// ==========Mac==========
public class Mac extends Platform {public Mac(Video video){this.video = video;}@Overridepublic void play() {System.out.println("mac platform play:");this.video.format();}
}
package com.bridge;// ==========Windows==========
public class Windows extends Platform{public Windows(Video video){this.video = video;}@Overridepublic void play() {System.out.println("windows platform play:");this.video.format();}
}
package com.bridge;public class Test {public static void main(String[] args) {// ==========Windows==========// ==========Mpeg=============Platform winMpeg = new Windows(new Mpeg());winMpeg.play();// ==========Linux==========// ==========Wmv=============Platform linuxWmv = new Linux(new Wmv());linuxWmv.play();// ==========Mac==========// ==========Avi==========Mac macAvi = new Mac(new Avi());macAvi.play();}
}
# 输出
windows platform play:
mpeg format!
linux platform play:
wmv format!
mac platform play:
avi format!