装饰器模式、适配器模式
1.Decorator 装饰器模式
基本原理
装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能。这也是判断是否该用装饰器模式的一个重要的依据。除此之外,装饰器模式还有一个特点,那就是可以对原始类嵌套使用多个装饰器。为了满足这个应用场景,在设计的时候,装饰器类需要跟原始类继承相同的抽象类或者接口
- Component Interface:对象的接口(共可装饰类和装饰类使用)
- Component:可装饰的对象
- Decorator:装饰器类,将额外任务应用于组件的类,它还实现了相同的组件接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35interface IComponent { method(): string } //生成装饰器对象的类 class Component implements IComponent { method(): string { return 'Component Method' } } //装饰器类 class Decorator implements IComponent { #object: IComponent // 接受一个被装饰类 constructor(object: IComponent) { this.#object = object } method(): string { return `Decorator Method(${this.#object.method()})` } } const COMPONENT = new Component() console.log(COMPONENT.method()) //Component Method // Component类被Decorator类装饰 const Decorated = new Decorator(COMPONENT) console.log(Decorated.method()) //Decorator Method(Component Method) //被装饰过的类Component可以在被装饰(套娃咯) const Decorated2 = new Decorator(Decorated) console.log(Decorated2.method()) //Decorator Method(Decorator Method(Component Method))
应用举例
让我们创建一个名为Value类来保存一个数组,然后添加对数字(Value
)进行加法 (Add
)和减法 (Sub
) 的装饰器来实现给对象添加新的功能,而不改变对象本身的。
Add
和 Sub
装饰器可以直接接受数字、自定义 Value
对象或其他 Add
和 Sub
装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57interface IValue { value: number } class Sub implements IValue { value: number constructor(val1: IValue | number, val2: IValue | number) { const left = Object.prototype.hasOwnProperty.call(val1, 'value') ? (val1 as IValue).value : (val1 as number) const right = Object.prototype.hasOwnProperty.call(val2, 'value') ? (val2 as IValue).value : (val2 as number) this.value = left - right } } class Add implements IValue { value: number constructor(val1: IValue | number, val2: IValue | number) { const left = Object.prototype.hasOwnProperty.call(val1, 'value') ? (val1 as IValue).value : (val1 as number) const right = Object.prototype.hasOwnProperty.call(val2, 'value') ? (val2 as IValue).value : (val2 as number) this.value = left + right } } //装饰器类 class Value implements IValue { value: number constructor(value: number) { this.value = value } } //装饰器 const A = new Value(1) const B = new Value(2) const C = new Value(5) console.log(new Add(A, B).value) //3 console.log(new Add(A, 100).value) //101 console.log(new Sub(C, A).value) //4 console.log(new Sub(new Add(C, B), A).value) //6 console.log(new Sub(100, 101).value) //-1 console.log(new Add(new Sub(new Add(C, B), A), 100).value)//106 console.log(new Sub(123, Add(C, C)).value)//113 console.log(new Add(new Sub(new Add(C, 10), A), 100).value) //114 console.log(A.value) //1 console.log(B.value) //2 console.log(C.value) //5
2.Adapter适配器模式
一个比较常用构造型设计模式——Adapter适配器模式,关于适配器模式,我们主要需要学习它的两种实现方式,类适配器和对象适配器,以及 5 种常见的应用场景
基本原理
适配器模式的英文翻译是 Adapter Design Pattern。顾名思义,这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。对于这个模式,有一个经常被拿来解释它的例子,就是 USB 转接头充当适 配器,把两种不兼容的接口,通过转接变得可以一起工作。
比如:你可能有两个相似的类,但它们具有不同的方法签名,因此你在其中一个方法签名之上创建一个适配器,以便更容易在调用时中实现和扩展
适配器模式与前面的装饰器模式有些类似,都是创建完对象后使用,不过设配器模式不能像装饰器模式一样递归调用
- Target: 需要适配的目标接口/类
- Adapter:适配器类
- Adapter Interface: 适配器需要实现的接口,以使目标与客户端兼容(插口和线同)
- Client:调用适配器的应用程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55// Adapter Concept Sample Code interface IA { methodA(): void } class ClassA implements IA { methodA() { console.log('method A') } } interface IB { methodB(): void } class ClassB implements IB { methodB() { console.log('method B') } } class ClassBAdapter implements IA { //ClassB中没有methodA,所以就需要创建适配器来兼容 #classB: ClassB constructor() { this.#classB = new ClassB() } methodA() { 'calls the class b method_b instead' this.#classB.methodB() } } const ITEMS = [new ClassA(), new ClassB()] ITEMS.forEach((item) => { if (item instanceof ClassB) { item.methodB() } else { item.methodA() } }) const ADAPTED = [new ClassA(), new ClassBAdapter()] ADAPTED.forEach((item) => { item.methodA() }) method A method B method A method B
就只是在外部包了一层,因此除了上面的对象适配器还有一种称为类适配器也是同样的效果,类适配器则是采用继承来实现,将将原method继承到复合Target接口的method上,比上面的示例还简单,这里就不写出示例了。
而具体选用那种需要根据实际情况选择
应用举例
假设有一个使用不同工具生产立方体的情形,而不同的工具是由不同的公司发明的,应用程序通过UI界面输入width、height、depth来生产立方体(接口),而输入的这些参数只与A公司的生产工具所需参数相同,而B公司的生产工具的所需参数与A公司并不同(接口也就不同了),那么为了连个接口适配,将B公司的生产工具适配A公司生产工具的接口。
这样在有一个公司(供应商)在忙时就可以使用另一个供应商了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97interface ICubeA { manufacture(width: number, height: number, depth: number): boolean } class CubeA implements ICubeA { static last_time = Date.now() manufacture(width: number, height: number, depth: number): boolean { //如果是忙碌中则制作一个正方体 const now = Date.now() if (now > CubeA.last_time + 1500) { console.log( `Company A built Cube with dimensions ${width}x${height}x${depth}` ) CubeA.last_time = now return true } return false //忙碌中 } } //一个假想的B公司的立方体制作工具 interface ICubeB { create( top_left_front: [number, number, number], bottom_right_back: [number, number, number] ): boolean } class CubeB implements ICubeB { static last_time = Date.now() create( top_left_front: [number, number, number], bottom_right_back: [number, number, number] ): boolean { // 如果不忙,那就用坐标制造一个立方体 const now = Date.now() if (now > CubeB.last_time + 3000) { console.log( `Company B built Cube with coords [${top_left_front[0]},${top_left_front[1]},${top_left_front[2]}],[${bottom_right_back[0]},${bottom_right_back[1]},${bottom_right_back[2]}]` ) CubeB.last_time = now return true } else { return false // busy } } } //适配器类,使CubeB类也能使用ICubeA接口 export default class CubeBAdapter implements ICubeA { #cube: CubeB constructor() { this.#cube = new CubeB() } manufacture(width: number, height: number, depth: number): boolean { const success = this.#cube.create( [0 - width / 2, 0 - height / 2, 0 - depth / 2], [0 + width / 2, 0 + height / 2, 0 + depth / 2] ) return success } } const totalCubes = 5 let counter = 0 const manufactureCube = () => { const width = Math.floor(Math.random() * 10) + 1 const height = Math.floor(Math.random() * 10) + 1 const depth = Math.floor(Math.random() * 10) + 1 let cube = new CubeA() let success = cube.manufacture(width, height, depth) if (success) { counter = counter + 1 } else { // try other manufacturer console.log('Company A was busy, so trying company B') cube = new CubeBAdapter() success = cube.manufacture(width, height, depth) if (success) { counter = counter + 1 } else { console.log('Company B was busy, so trying company A') } } } // wait some time between manufacturing each cube const interval = setInterval(() => { manufactureCube() if (counter >= totalCubes) { clearInterval(interval) console.log(`${totalCubes} cubes have been manufactured`) } }, 1000)
1
2
3
4
5
6
7
8
9
10
11
12
13Company A was busy, so trying company B Company B was busy, so trying company A Company A built Cube with dimensions 6x5x10 Company A was busy, so trying company B Company B built Cube with coords [-4,-3,-2.5],[4,3,2.5] Company A built Cube with dimensions 4x5x3 Company A was busy, so trying company B Company B was busy, so trying company A Company A built Cube with dimensions 10x2x1 Company A was busy, so trying company B Company B built Cube with coords [-0.5,-2,-2.5],[0.5,2,2.5] 5 cubes have been manufactured
最后
以上就是大胆萝莉最近收集整理的关于装饰器模式、适配器模式装饰器模式、适配器模式的全部内容,更多相关装饰器模式、适配器模式装饰器模式、适配器模式内容请搜索靠谱客的其他文章。
发表评论 取消回复