JAVA SCRIPT设计模式是本人根据GOF的设计模式写的博客记录。使用JAVA SCRIPT语言来实现主体功能,所以不可能像C++,JAVA等面向对象语言一样严谨,大部分程序都附上了JAVA SCRIPT代码,代码只是实现了设计模式的主体功能,不代表全部的正确,特此声明。若读者需要了解设计模式目录、原则、设计变化方向,环境相关等信息请查看设计模式开篇。
一、UML类图
参与者:
1.1 Target(Shape)
- 定义Client使用的与特定领域相关的接口。
1.2 Client(DrawingEditor)
- 与符合Target接口的对象协同。
1.3 Adaptee(TextView)
- 定义一个已经存在的接口,这个接口需要适配。
1.4 Adapter(TextShape)
- 对Adaptee的接口与Target接口进行适
二、意图
将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
三、适用性
- 你想使用一个已经存在的类,而它的接口不符合你的需求。
- 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
- (仅适用于对象Adapter)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
四、示例代码
4.1 动机
有时,为复用而设计的工具箱类不能够被复用的原因仅仅是因为它的接口与专业应用领域所需要的接口不匹配。
例如,有一个绘图编辑器,这个编辑器允许用户绘制和排列基本图元(线、多边型和正文等)生成图片和图表。这个绘图编辑器的关键抽象是图形对象。图形对象有一个可编辑的形状,并可以绘制自身。图形对象的接口由一个称为Shape的抽象类定义。绘图编辑器为每一种图形对象定义了一个Shape的子类:LineShape类对应于直线,PolygonShape类对应于多边型,等等。
像LineShape和PolygonShape这样的基本几何图形的类比较容易实现,这是由于它们的绘图和编辑功能本来就很有限。但是对于可以显示和编辑正文的TextShape子类来说,实现相当困难,因为即使是基本的正文编辑也要涉及到复杂的屏幕刷新和缓冲区管理。同时,成品的用户界面工具箱可能已经提供了一个复杂的TextView类用于显示和编辑正文。理想的情况是我们可以复用这个TextView类以实现TextShape类,但是工具箱的设计者当时并没有考虑Shape的存在,因此TextView和Shape对象不能互换。
一个应用可能会有一些类具有不同的接口并且这些接口互不兼容,在这样的应用中象TextView这样已经存在并且不相关的类如何协同工作呢?我们可以改变TextView类使它兼容Shape类的接口,但前提是必须有这个工具箱的源代码。然而即使我们得到了这些源代码,修改TextView也是没有什么意义的;因为不应该仅仅为了实现一个应用,工具箱就不得不采用一些与特定领域相关的接口。
我们可以不用上面的方法,而定义一个TextShape类,由它来适配TextView的接口和Shape的接口。我们可以用两种方法做这件事:1)继承Shape类的接口和TextView的实现,或2)将一个TextView实例作为TextShape的组成部分,并且使用TextView的接口实现TextShape。这两种方法恰恰对应于Adapter模式的类和对象版本。我们将TextShape称之为适配器Adapter。
本例说明了在Shape类中声明的BoundingBox请求如何被转换成在TextView类中定义的GetExtent请求。由于TextShape将TextView的接口与Shape的接口进行了匹配,因此绘图编辑器就可以复用原先并不兼容的TextView类。
Adapter时常还要负责提供那些被匹配的类所没有提供的功能。由于绘图编辑器允许用户交互的将每一个Shape对象“拖动”到一个新的位置,而TextView设计中没有这种功能。我们可以实现TextShape类的CreateManipulator操作,从而增加这个缺少的功能,这个操作返回相应的Manipulator子类的一个实例。
Manipulator是一个抽象类,它所描述的对象知道如何驱动Shape类响应相应的用户输入,例如将图形拖动到一个新的位置。对应于不同形状的图形,Manipulator有不同的子类;例如子类TextManipulator对应于TextShape。TextShape通过返回一个TextManipulator实例,增加了TextView中缺少而Shape需要的功能。
4.2 示例UML
目录结构:
4.2 Target(Shape)
- 定义Client使用的与特定领域相关的接口。
export default class Shape {
constructor() {
}
BoundingBox() {
}
CreateManipulator() { //返回 Manipulator //操纵者; 控制者; 设计模式----抽象方法
}
}
4.3 Client(DrawingEditor)
- 与符合Target接口的对象协同。
import Shape from './Shape/Shape.js';
import TextShape from './Shape/impl/TextShape.js';
import Line from './Shape/impl/Line.js';
export default class DrawingEditor{
main(){
let line=new Line();
line.BoundingBox();
let lineManipulator=line.CreateManipulator();
lineManipulator.Drag();
let textShape=new TextShape();
textShape.BoundingBox();
let textManipulator=textShape.CreateManipulator();
textManipulator.Drag();
}
}
4.4 Adaptee(TextView)
- 定义一个已经存在的接口,这个接口需要适配。
export default class TextView {
constructor() {
}
GetExtent() {
console.log(` 这里的TextView 类方法被适配到了Shape 的BdoundingBox方法 `);
}
}
4.5 Adapter(TextShape)
- 对Adaptee的接口与Target接口进行适
import Shape from '../Shape.js';
import TextView from './TextView.js';
import TextManipulator from '../../Manipulator/impl/TextManipulator.js';
export default class TextShape extends Shape {
#textView;//被适配的类对象
constructor() {
super();
this.#textView=new TextView();
}
BoundingBox() {
this.#textView.GetExtent();
}
CreateManipulator() { //操纵者; 控制者;
return new TextManipulator();
}
}
4.6 测试HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="module" >
import Client from './DrawingEditor.js';
let cl=new Client();
cl.main()
</script>
</head>
<body>
</body>
</html>
测试结果:
Line.js:11 Line 的BdoundingBox方法
LineManipulator.js:10 TextManipulator Drag
TextView.js:6 这里的TextView 类方法被适配到了Shape 的BdoundingBox方法
TextManipulator.js:10 TextManipulator Drag
五、源代码下载
下载链接:https://pan.baidu.com/s/1XuPqp84cccBNVkbnMY3sKw
提取码:q2ut