手写场景 | 实现lazyMan

题目介绍

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
实现一个LazyMan,可以按照以下方式调用:
LazyMan("Hank")输出:
Hi! This is Hank!

LazyMan("Hank").sleep(10).eat("dinner")
输出
Hi! This is Hank!
//等待10秒..
Wake up after 10
Eat dinner~

LazyMan("Hank").eat("dinner").eat("supper")
输出
Hi This is Hank!
Eat dinner~
Eat supper~

LazyMan("Hank").sleepFirst(5).eat("supper")
输出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper

以此类推

考察知识点

  • 方法链式调用
  • 类的使用和面向对象编程的思路
  • 设计模式引用
  • 代码解耦
  • 最少知识原则
  • 代码的书写结果和命名

题目解析

  1. 看题目输出示例,这是一个拟人化的输出 => 定义一个名为LazyMan的类,类里面有sayNameeatsleep等方法
  2. 从输出结果来看:sleepFirst的优先级最高,其余的行为优先级一致
  3. LazyMan首先需要初始化人,才能继续后面的行为,因此LazyMan是一个接口 => sayName方法一定在构造函数中
  4. 按调用的方法次序进行顺序执行,是一个队列

实现思路及代码

(1)任务队列实现

这种模式类似于中间件模式,其核心是next方法,每当队列中的一个方法执行完都会调用next方法来执行队列中的另一个方法,直到全部执行完成

构造函数中需要setTimeout保证队列开始执行的时间是在下一个事件循环中,从而确保当前的链式调用中的所有行为在调用之前被加载进队列中

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
class _LazyMan {
constructor(name) {
this.tasks = [];
this.sayName(name);

setTimeout(() => {
this.next();
})
};

next() {
const task = this.tasks.shift(); // 拿出队列最前面的方法,并且要在队列里面删除它
task && task();
};

sayName(name) {
const task = () => {
console.log(`Hi! This is ${name}!`);
this.next();
};
this.tasks.push(task);
};

sleep(time) {
this.tasks.push(this._sleepWrapper(time));
return this;
};

sleepFirst(time) {
this.tasks.unshift(this._sleepWrapper(time));
return this;
};

_sleepWrapper(time) {
return () => {
setTimeout(() => {
console.log(`Wake up afeter ${time} second`);
this.next();
}, time * 1000);
}
};


eat(type) {
const task = () => {
console.log(`Eat ${type}~`)
this.next();
};
this.tasks.push(task);
return this;
};
}


const LazyMan = (name) => new _LazyMan(name);

LazyMan("Hank").sleepFirst(5).eat("supper")

/*
Wake up afeter 5 second
Hi! This is Hank!
Eat supper~
*/

(2)任务队列 + Promise实现

用Promise代替next调用方法

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
class _LazyMan {
constructor(name) {
this.tasks = [];
this.sayName(name);

Promise.resolve().then(() => {
let task = Promise.resolve();
this.tasks.forEach(item => {
task = task.then(item);
})
})
};

sayName(name) {
const task = () => {
console.log(`Hi! This is ${name}!`);
};
this.tasks.push(task);
};

sleep(time) {
this.tasks.push(this._sleepWrapper(time));
return this;
};

sleepFirst(time) {
this.tasks.unshift(this._sleepWrapper(time));
return this;
};

_sleepWrapper(time) {
return () => new Promise(resolve => {
setTimeout(() => {
console.log(`Wake up afeter ${time} second`);
resolve();
}, time * 1000);
})
};


eat(type) {
this.tasks.push(() => {
console.log(`eat ${type}`);
})
return this;
};
}


const LazyMan = (name) => new _LazyMan(name);

LazyMan("Hank").sleepFirst(5).eat("supper")

/*
Wake up afeter 5 second
Hi! This is Hank!
Eat supper~
*/

(3)任务队列 + async实现

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
class _LazyMan {
constructor(name) {
this.tasks = [];
this.sayName(name);

setTimeout(async () => {
for (let task of this.tasks) {
await task();
}
})
};

sayName(name) {
const task = () => {
console.log(`Hi! This is ${name}!`);
};
this.tasks.push(task);
};

sleep(time) {
this.tasks.push(this._sleepWrapper(time));
return this;
};

sleepFirst(time) {
this.tasks.unshift(this._sleepWrapper(time));
return this;
};

_sleepWrapper(time) {
return () => new Promise(resolve => {
setTimeout(() => {
console.log(`Wake up afeter ${time} second`);
resolve();
}, time * 1000);
})
};


eat(type) {
this.tasks.push(() => {
console.log(`eat ${type}`);
})
return this;
};
}


const LazyMan = (name) => new _LazyMan(name);

LazyMan("Hank").sleepFirst(5).eat("supper")

/*
Wake up afeter 5 second
Hi! This is Hank!
Eat supper~
*/

参考

LazyMan的深入解析和实现

多种方式实现 LazyMan

如何实现一个LazyMan?

LazyMan 有几样写法,你知道么?