Adapter Design Pattern
Video Lecture
Overview
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.
Terminology
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.
Adapter UML Diagram

Source Code
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.
./src/adapter/adapter-concept.ts
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 does not have a methodA, so we can create an adapter
#classB: ClassB
constructor() {
this.#classB = new ClassB()
}
methodA() {
'calls the class b method_b instead'
this.#classB.methodB()
}
}
// The Client
// Before the adapter I need to test the objects class to know which
// method to call.
const ITEMS = [new ClassA(), new ClassB()]
ITEMS.forEach((item) => {
if (item instanceof ClassB) {
item.methodB()
} else {
item.methodA()
}
})
// After creating an adapter for ClassB I can reuse the same method
// signature as ClassA (preferred)
const ADAPTED = [new ClassA(), new ClassBAdapter()]
ADAPTED.forEach((item) => {
item.methodA()
})
|
Output
node ./dist/adapter/adapter-concept.js
method A
method B
method A
method B
Adapter Use Case
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.
Example UML Diagram

Source Code
./src/adapter/client.ts
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 | // Adapter Example Use Case
import CubeA from './cube-a'
import CubeBAdapter from './cube-b-adapter'
const totalCubes = 5
let counter = 0
const manufactureCube = () => {
// produce 5 cubes from which ever supplier can manufacture it first
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)
|
./src/adapter/cube-a.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | // A hypothetical Cube tool from Company A
export interface ICubeA {
manufacture(width: number, height: number, depth: number): boolean
}
export default class CubeA implements ICubeA {
static last_time = Date.now()
manufacture(width: number, height: number, depth: number): boolean {
// if not busy, then manufacture a cube with dimensions
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 // busy
}
}
|
./src/adapter/cube-b.ts
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 | // A hypothetical Cube tool from Company B
export interface ICubeB {
create(
top_left_front: [number, number, number],
bottom_right_back: [number, number, number]
): boolean
}
export default class CubeB implements ICubeB {
static last_time = Date.now()
create(
top_left_front: [number, number, number],
bottom_right_back: [number, number, number]
): boolean {
// if not busy, then manufacture a cube with coords
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
}
}
}
|
./src/adapter/cube-b-adapter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | // Adapter for CubeB that implements ICubeA
import { ICubeA } from './cube-a'
import CubeB from './cube-b'
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
}
}
|
Output
node ./dist/adapter/client.js
Company 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
Summary
... To read hidden text, either pause Video Lectures, refer to Book or subscribe to Medium Membership.