前言
同学们,上一章我们介绍了组合模式,组合模式是一种基于树状结构的设计模式,组合模式中的对象是满足一致性的,这样可以让用户不再需要去考虑对象的特殊性,从而达到一种一视同仁的效果。这一章我们将继续介绍一种新的设计模式,模板方法模式
正文
模板方法的定义
我们之前多次提到,javascript不是一门基于类编程的语言,javascript的继承不需要通过类,而是可以通过原型克隆来实现,模板方法就是一种基于继承的非常简单的设计模式。
模板方法由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类,子类通过继承抽象类,也继承了整个算法结构。
模板方法的实现
一如既往,在讲述模板方法的实现前,我们先引入一个业务场景,假设我们需要泡咖啡,我们需要走哪几个步骤呢,把水煮沸,把咖啡倒入杯中,倒入沸水,加入糖和牛奶,我们不难封装一个对象来阐述这个行为
var makeCoffee = function() {}
makeCoffee.prototype.boiling = function() {
console.log('把水煮沸');
}
makeCoffee.prototype.intoMaterial = function() {
console.log('把咖啡倒入杯中');
}
makeCoffee.prototype.intoWater = function() {
console.log('倒入沸水');
}
makeCoffee.prototype.intoBurdening = function() {
console.log('加入糖和牛奶');
}
makeCoffee.prototype.init = function() {
this.boiling();
this.intoMaterial();
this.intoWater();
this.intoBurdening();
}
这样泡咖啡的对象就封装好了,但是喝完咖啡又想喝奶茶咋整,咱们看看泡奶茶需要哪几个步骤,把水煮沸,把红茶叶倒入杯中,倒入沸水,加入牛奶和糖,这时候很多同学们可能就已经跃跃欲试想再封装一个泡牛奶的对象了,但是大家有没有发现泡奶茶的步骤喝泡咖啡的相比其实有很多相似的地方,除了一个放的是茶叶另一个放的是咖啡,我们是不是可以封装一个共同的对象给他们去继承呢
var beverage = function() {}
beverage.prototype.boiling = function() {
console.log('把水煮沸');
}
beverage.prototype.intoMaterial = function() {} // 空方法留给子类去实现
beverage.prototype.intoWater = function() {
console.log('倒入沸水');
}
beverage.prototype.intoBurdening = function() {} // 空方法留给子类去实现
beverage.prototype.init = function() {
this.boiling();
this.intoMaterial();
this.intoWater();
this.intoBurdening();
}
这样一个通用的饮料对象就封装好了,你可以理解成是基于类的语言中的抽象类,这样对于茶和咖啡,我们只需要用beverage新建一个对象并且补充它原型中的子类方法就好
javascript中实现模板方法的注意事项
与传统基于类的语言不同,javascript没有类似抽象类或者接口来帮助检查超类中的方法一定被实现,像上面的例子,如果在实现利用beverage实现茶对象或者咖啡对象的时候,没有实现intoMaterial和intoBurdening方法,就会导致对象init时候的结果与预期的不符,这个在javascript中只能依靠程序员的自觉或者在实现父对象的时候,对要实现的方法抛出一个错误,这样在继承后没有重写的情况下就会抛出错误起到一个提醒的作用
var beverage = function() {}
beverage.prototype.boiling = function() {
console.log('把水煮沸');
}
beverage.prototype.intoMaterial = function() {
throw new Error('子类必须重写intoMaterial方法');
}
beverage.prototype.intoWater = function() {
console.log('倒入沸水');
}
beverage.prototype.intoBurdening = function() {
throw new Error('子类必须重写intoBurdening方法');
}
beverage.prototype.init = function() {
this.boiling();
this.intoMaterial();
this.intoWater();
this.intoBurdening();
}
javascript中模板方法的实现
javascript不是一门基于类的语言,所以其实对于javascript而言,利用继承去实现模板方法是不那么必要的,我们完全可以利用高阶函数更清晰优雅地实现它
var beverage = function(params) {
var boiling = function() {
console.log('把水煮沸');
}
var intoMaterial = params.intoMaterial || function() {
throw new Error('子类必须重写intoMaterial方法');
}
var intoWater = function() {
console.log('倒入沸水');
}
var intoBurdening = params.intoBurdening || function() {
throw new Error('子类必须重写intoBurdening方法');
}
var F = function() {}
F.prototype.init = function() {
boiling();
intoMaterial();
intoWater();
intoBurdening();
}
return F;
}
通过这样我们只需要传入参数,就可以配置出对应的特殊饮料对象去用于继承
小结
模板方法是一种典型的通过封装变化来提高系统扩展性的设计模式,通过模板方法,我们可以创建新的子类,但是又不需要改动到父类和其他子类,满足了开放-封闭原则
小伙伴们今天的学习就到这里了,如果觉得本文对你有帮助的话,欢迎转发,评论,收藏,点赞!!!
每天学习进步一点点,就是领先的开始。如果想继续提高,欢迎关注我,或者关注公众号”祯民讲前端“。大量前端技术文章,面试资料,技巧等助你更进一步!