前言
这道面试题做起来其实并不难,无非就是定义一些函数,将泡茶的过程加入进去,再加入一个茶叶对象,用这个对象调用这些方法输出即可,但这其实并非是在考察你的代码的能力,而是在考察你关于模板方法模式这一设计模式的了解,接下来就由我来结合泡茶来为大家讲述小白眼里的这一设计模式。
模板方法模式
来让我们想一想,泡茶是一些什么步骤?
第一步 - 把水烧开。
第三步 - 把烧开的水倒在茶包上。
第五步 - 取出茶包。
第六步 - 如果需要,加入糖或牛奶调味。
那么代码就好实现了
function Tea(type){
this.type = type
console.log('您准备泡一杯' + this.type);
}
var lemonTea = new Tea('柠檬茶');
这段代码建立了一个名为Tea的构造函数。
而这就是模板方法模式的关键一:利用构造函数来构建相似对象
在es6之前版本的JS中并没有class的概念,而是通过类似的方法来模拟类行为,即使用构造函数和原型链的方法。
通过Tea对象(在JS中,除了简单数据类型,就是对象(函数是可执行的对象))构建的lemonTea对象,它就是以Tea为原型的对象,而这就是JS和GO都比较推崇的原型式面向对象。那这样构建一个茶叶对象有什么好处呢?
- 代码复用:构造函数允许你定义一个通用的模板来创建具有相似属性和方法的对象。这意味着你不需要为每一个对象重复编写相同的属性设置和方法定义代码。
- 对象初始化:构造函数内可以执行初始化逻辑,确保新创建的对象在开始使用前就已经具备了必要的状态或进行了恰当的设置。这对于保证对象的完整性非常有用。
- 易于理解和维护:构造函数模式使得代码结构更加清晰,易于阅读和理解。通过查看构造函数,可以快速了解对象应具有的属性和行为,有助于代码的维护和后续开发。
- 继承和多态:结合原型链,构造函数能够支持面向对象编程中的继承特性,使得子类可以继承父类的属性和方法,并可以覆写或扩展它们,实现多态性。这种机制促进了代码的模块化和组件化。
- 封装性:通过构造函数和原型,可以将对象的状态(属性)和行为(方法)封装在一起,隐藏内部实现细节,仅通过公共接口与外部交互,提高了代码的安全性和模块间的独立性。
- 灵活性:构造函数可以通过接收参数来动态地调整对象的初始化过程,使得同一构造函数可以创建出不同配置或状态的对象,增加了程序的灵活性和适应性。
而这里我们只是利用它的复用性以及继承
Tea.prototype.boilWater = function(){
console.log('把水煮沸');
}
Tea.prototype.steepTeaBag = function(){
console.log('用沸水煮茶叶');
}
Tea.prototype.pourInCup = function(){
console.log('把茶水倒进杯子');
}
Tea.prototype.addLemon = function(){
console.log('加柠檬');
}
我们利用prototype关键字构建了一系列泡茶的方法。
prototype是JS中用于实现对象继承和共享方法的关键机制,它允许对象实例访问其构造函数原型上的属性和方法,从而促进代码复用和高效内存使用。而prototype自身则其实是构造函数(Tea)的一个属性,通过构造函数构建的对象(lemonTea)其内部的内部[[Prototype]](也就是常说的隐式原型)会被设置为构造函数的prototype对象,这意味着新对象(lemonTea)可以访问到构造函数prototype上定义的所有属性和方法
这我们就可以就可以完成这个题目了,接下来用lemonTea来调用这些函数就行了
lemonTea.boilWater();
lemonTea.steepTeaBag();
lemonTea.pourInCup();
lemonTea.addLemon();
结果就是
但如果我们以后要泡茶呢?还是要经过这么复杂的步骤(一个个的调用函数)吗?答案当然是不,因为这代表着我们的代码还能优化,所以还没结束
这里就要引出模板方法模式的关键点二了:接口(init)
接口函数并并不需要有自己独特的作用,它只需要将重复的过程简化,而在本题中,它的作用是这样的
Tea.prototype.init = function(){
this.boilWater();
this.steepTeaBag();
this.pourInCup();
this.addLemon();
}
lemonTea.init();
这样我们以后要“泡茶”就只需要调用这个接口函数就行了,而且这也能更方便的维护我们的代码。
结语
总结来说,这段代码展示了如何使用JS的原型链和构造函数来实现模板方法模式,其中Tea类定义了泡茶的基本步骤作为模板,而具体的茶类(如这里的柠檬茶)可以通过继承和覆盖部分步骤来实现特定的泡制过程,同时保持整体流程结构的一致性。
我是Ace,我们下次分享再见!!!