题目介绍 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 以此类推
考察知识点
方法链式调用
类的使用和面向对象编程的思路
设计模式引用
代码解耦
最少知识原则
代码的书写结果和命名
题目解析
看题目输出示例,这是一个拟人化的输出 => 定义一个名为LazyMan
的类,类里面有sayName
、eat
、sleep
等方法
从输出结果来看:sleepFirst
的优先级最高,其余的行为优先级一致
LazyMan
首先需要初始化人,才能继续后面的行为,因此LazyMan
是一个接口 => sayName
方法一定在构造函数中
按调用的方法次序进行顺序执行,是一个队列
实现思路及代码 (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" )
(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" )
(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" )
参考 LazyMan的深入解析和实现
多种方式实现 LazyMan
如何实现一个LazyMan?
LazyMan 有几样写法,你知道么?