JAVA SCRIPT设计模式是本人根据GOF的设计模式写的博客记录。使用JAVA SCRIPT语言来实现主体功能,所以不可能像C++,JAVA等面向对象语言一样严谨,大部分程序都附上了JAVA SCRIPT代码,代码只是实现了设计模式的主体功能,不代表全部的正确,特此声明。若读者需要了解设计模式目录、原则、设计变化方向,环境相关等信息请查看设计模式开篇。
一、UML类图
参与者:
1.1 Abstraction(Window)
- 定义抽象类的接口。
- 维护一个指向Implementor类型对象的指针。
1.2 RefinedAbstraction(IconWindow)
- 扩充由Abstraction定义的接口。
1.3 Implementor(WindowImp)
- 定义实现类的接口,该接口不一定要与Abstraction的接口完全一致;事实上这两个接口可以完全不同。一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作。
1.4 ConcreteImplementor(XwindowImp,PMWindowImp)
- 实现Implementor接口并定义它的具体实现。
二、意图
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
三、适用性
- 你不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换。
- 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时Bridge模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。。
- 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。
- (C++)你想对客户完全隐藏抽象的实现部分。在C++中,类的表示在类接口中是可见的。
四、优点和缺点
Bridge模式有以下一些优点:
- 分离接口及其实现部分一个实现未必不变地绑定在一个接口上。抽象类的实现可以在运行时刻进行配置,一个对象甚至可以在运行时刻改变它的实现。将Abstraction与Implementor分离有助于降低对实现部分编译时刻的依赖性,当改变一个实现类时,并不需要重新编译Abstraction类和它的客户程序。为了保证一个类库的不同版本之间的二进制兼容性,一定要有这个性质。另外,接口与实现分离有助于分层,从而产生更好的结构化系统,系统的高层部分仅需知道Abstraction和Implementor即可。
- 提高可扩充性你可以独立地对Abstraction和Implementor层次结构进行扩充。
- 实现细节对客户透明你可以对客户隐藏实现细节,例如共享Implementor对象以及相应的引用计数机制(如果有的话)。
五、示例代码
5.1 动机
当一个抽象可能有多个实现时,通常用继承来协调它们。抽象类定义对该抽象的接口,而具体的子类则用不同方式加以实现。但是此方法有时不够灵活。继承机制将抽象部分与它
的实现部分固定在一起,使得难以对抽象部分和实现部分独立地进行修改、扩充和重用。
让我们考虑在一个用户界面工具箱中,一个可移植的Window抽象部分的实现。例如,这一抽象部分应该允许用户开发一些在X Window System和IBM的Presentation Manager(PM)系
统中都可以使用的应用程序。运用继承机制,我们可以定义Window抽象类和它的两个子类XWindow与PMWindow,由它们分别实现不同系统平台上的Window界面。但是继承机制有两个不足之处:
- 扩展Window抽象使之适用于不同种类的窗口或新的系统平台很不方便。假设有Window的一个子类IconWindow,它专门将Window抽象用于图标处理。为了使IconWindow支持两个系统平台,我们必须实现两个新类XIconWindow和PMIconWindow,更为糟糕的是,我们不得不为每一种类型的窗口都定义两个类。而为了支持第三个系统平台我们还必须为每一种窗口定义一个新的Window子类,如下图所示。
- 继承机制使得客户代码与平台相关。每当客户创建一个窗口时,必须要实例化一个具体的类,这个类有特定的实现部分。例如,创建Xwindow对象会将Window抽象与XWindow的实现部分绑定起来,这使得客户程序依赖于XWindow的实现部分。这将使得很难将客户代码移植到其他平台上去。
客户在创建窗口时应该不涉及到其具体实现部分。仅仅是窗口的实现部分依赖于应用运行的平台。这样客户代码在创建窗口时就不应涉及到特定的平台。
Bridge模式解决以上问题的方法是,将Window抽象和它的实现部分分别放在独立的类层次结构中。其中一个类层次结构针对窗口接口(Window、IconWindow、TransientWindow 临时),
另外一个独立的类层次结构针对平台相关的窗口实现部分,这个类层次结构的根类为WindowImp。例如XwindowImp子类提供了一个基于XWindow系统的实现,如下页上图所示。
对Window子类的所有操作都是用WindowImp接口中的抽象操作实现的。这就将窗口的抽象与系统平台相关的实现部分分离开来。因此,我们将Window与WindowImp之间的关系称之
为桥接,因为它在抽象类与它的实现之间起到了桥梁作用,使它们可以独立地变化。
5.2 示例UML
目录结构:
5.2 Abstraction(Window)
- 定义抽象类的接口。
- 维护一个指向Implementor类型对象的指针。
import WindowImp from '../WindowImp/WindowImp.js';
export default class Window {
windowImp;
constructor(windowImp) {
this.windowImp=windowImp;
}
DrawText() {
this.windowImp.DevDrawText();
}
DrawRect() {
console.log(` Window 的DrawRect方法 `);
this.windowImp.DevDrawLine();
this.windowImp.DevDrawLine();
this.windowImp.DevDrawLine();
this.windowImp.DevDrawLine();
}
}
5.3 RefinedAbstraction(IconWindow)
- 扩充由Abstraction定义的接口。
import Window from '../Window.js';
export default class IconWindow extends Window {
constructor(windowImp) {
super(windowImp);
}
DrawBorder() {
this.DrawText();
this.DrawRect();
}
}
5.4 Implementor(WindowImp)
- 定义实现类的接口,该接口不一定要与Abstraction的接口完全一致;事实上这两个接口可以完全不同。一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作。
export default class WindowImp {
constructor() {
}
DevDrawText() {
}
DevDrawRect() {
}
}
5.5 ConcreteImplementor(XwindowImp,PMWindowImp)
- 实现Implementor接口并定义它的具体实现。
import WindowImp from '../WindowImp.js';
export default class XWindowImp extends WindowImp {
constructor() {
super();
}
DevDrawText() {
console.log(` XWindowImp 的DevDrawText方法 `);
}
DevDrawLine() {
console.log(` XWindowImp 的DevDrawLine方法 `);
}
}
5.6 Client
import Window from './Window/Window.js';
import IconWindow from './Window/impl/IconWindow.js';
import TranslentWindow from './Window/impl/TranslentWindow.js';
import XWindowImp from './WindowImp/impl/XWindowImp.js';
export default class Client{
main(){
let iconwindow =new IconWindow(new XWindowImp() );//Window
let tranwindow =new TranslentWindow(new XWindowImp() );//Window
iconwindow.DrawBorder();
tranwindow.DrawCloseBox();
}
}
5.7 测试HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="module" >
import Client from './Client.js';
let cl=new Client();
cl.main()
</script>
</head>
<body>
</body>
</html>
测试结果:
XWindowImp.js:9 XWindowImp 的DevDrawText方法
Window.js:14 Window 的DrawRect方法
XWindowImp.js:12 XWindowImp 的DevDrawLine方法
XWindowImp.js:12 XWindowImp 的DevDrawLine方法
XWindowImp.js:12 XWindowImp 的DevDrawLine方法
XWindowImp.js:12 XWindowImp 的DevDrawLine方法
Window.js:14 Window 的DrawRect方法
XWindowImp.js:12 XWindowImp 的DevDrawLine方法
XWindowImp.js:12 XWindowImp 的DevDrawLine方法
XWindowImp.js:12 XWindowImp 的DevDrawLine方法
XWindowImp.js:12 XWindowImp 的DevDrawLine方法
六、源代码下载
下载链接:https://pan.baidu.com/s/1XuPqp84cccBNVkbnMY3sKw
提取码:q2ut