JavaScript模板方法模式

编程入门 行业动态 更新时间:2024-10-27 03:40:48

JavaScript<a href=https://www.elefans.com/category/jswz/34/1770549.html style=模板方法模式"/>

JavaScript模板方法模式

JavaScript模板方法模式

  • 1 什么是模板方法模式
  • 2 Coffee or Tea
  • 3 钩子方法
  • 4 好莱坞原则

1 什么是模板方法模式

模板方法模式是一种只需使用继承就可以实现的模式。

模板方法模式由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。

通常在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。

2 Coffee or Tea

接下来通过咖啡与茶这个经典的例子来说明模版方法模式。

首先,我们想泡一杯咖啡,泡咖啡的步骤通常如下:

  1. 把水煮沸
  2. 用沸水冲泡咖啡
  3. 将咖啡倒入杯子中
  4. 添加糖和牛奶

将上述步骤写成代码描述出来,具体如下:

var Coffee = function () {};Coffee.prototype.boilWater = function () {console.log("把水煮沸");
};Coffee.prototype.brewCoffeeGriends = function () {console.log("用沸水冲泡咖啡");
};Coffee.prototype.pourInCup = function () {console.log("把咖啡倒进杯子");
};Coffee.prototype.addSugarAndMilk = function () {console.log("加糖和牛奶");
};Coffee.prototype.init = function () {this.boilWater();this.brewCoffeeGriends();this.pourInCup();this.addSugarAndMilk();
};var Coffee = new Coffee();
Coffee.init();

接下来,我们泡一壶茶,泡茶的步骤和泡咖啡的步骤基本相同:

  1. 把水煮沸
  2. 用沸水浸泡茶叶
  3. 将茶水倒入杯子中
  4. 添加柠檬

同样用一段代码来实现泡茶的步骤:

var Tea = function () {};Tea.prototype.boilWater = function () {console.log("把水煮沸");
};Tea.prototype.steepTeaBag = function () {console.log("用沸水浸泡茶叶");
};Tea.prototype.pourInCup = function () {console.log("把茶水倒进杯子");
};Tea.prototype.addLemon = function () {console.log("加柠檬");
};Tea.prototype.init = function () {this.boilWater();this.steepTeaBag();this.pourInCup();this.addLemon();
};var tea = new Tea();
tea.init();

经过对比泡咖啡和泡茶的过程,我们发现两者的步骤好像差不多,但是有如下不同点:

  • 原料不同。一个是咖啡,一个是茶,但我们可以把它们都抽象为“饮料”;
  • 泡的方式不同。咖啡是冲泡,而茶叶是浸泡,我们可以把它们都抽象为“泡”;
  • 加入的调料不同。一个是糖和牛奶,一个是柠檬,但我们可以把它们都抽象为“调料”;

经过抽象之后,不管是泡咖啡还是泡茶,我们都能整理为下面四步:

  1. 把水煮沸
  2. 用沸水冲泡饮料
  3. 将饮料倒入杯子中
  4. 添加调味料

根据上述共同点,我们可以创建一个抽象父类来表示泡一杯饮料的整个过程。不论是Coffee,还是Tea,都用Beverage来表示,代码如下:

Beverage.prototype.boilWater = function () {console.log("把水煮沸");
};Beverage.prototype.brew = function () {}; // 冲泡动作Beverage.prototype.pourInCup = function () {}; // 倒入杯子Beverage.prototype.addCondiments = function () {}; // 添加调料Beverage.prototype.init = function () {this.boilWater();this.brew();this.pourInCup();this.addCondiments();
};

接下来我们创建咖啡类和茶类,并让它们继承饮料类:

var Coffee = function () {};
Coffee.prototype = new Beverage();// 重写父类方法
Coffee.prototype.brew = function () {console.log("用沸水冲泡咖啡");
};
Coffee.prototype.pourInCup = function () {console.log("把咖啡倒进杯子");
};
Coffee.prototype.addCondiments = function () {console.log("加糖和牛奶");
};var Coffee = new Coffee();
Coffee.init();
var Tea = function () {};
Tea.prototype = new Beverage();// 重写父类方法
Tea.prototype.steepTeaBag = function () {console.log("用沸水浸泡茶叶");
};
Tea.prototype.pourInCup = function () {console.log("把茶水倒进杯子");
};
Tea.prototype.addCondiments = function () {console.log("加柠檬");
};var tea = new Tea();
tea.init();

在上面的例子中,Beverage.prototype.init就是模板方法,因为该方法中封装了子类的算法框架,它作为一个算法的模板,指导子类以何种顺序去执行哪些方法。

3 钩子方法

通过模板方法模式,我们在父类中封装了子类的算法框架。这些算法框架在正常状态下是适用于大多数子类的,但如果有一些特别“个性”的子类呢?比如有一些客人喝咖啡是不加调料(糖和牛奶)的。

既然Beverage作为父类,已经规定好了冲泡饮料的4个步骤,那么有什么办法可以让子类不受这个约束呢?

钩子方法可以用来解决这个问题,放置钩子是隔离变化的一种常见手段。我们在父类中容易变化的地方放置钩子,钩子可以有一个默认的实现,究竟要不要“挂钩”,这由子类自行决定。钩子方法的返回结果决定了模板方法后面部分的执行步骤,也就是程序接下来的走向,这样一来,程序就拥有了变化的可能。

接下来将挂钩customerWantsCondiments放入Beverage类,看看我们如何得到一杯不需要糖和牛奶的咖啡,代码如下:

var Beverage = function () {};
Beverage.prototype.boilWater = function () {console.log("把水煮沸");
};
Beverage.prototype.brew = function () {}; // 冲泡动作
Beverage.prototype.pourInCup = function () {}; // 倒入杯子
Beverage.prototype.addCondiments = function () {}; // 添加调料
Beverage.prototype.customerWantsCondiments = function () {return true; // 默认需要调料
};
Beverage.prototype.init = function () {this.boilWater();this.brew();this.pourInCup();if (this.customerWantsCondiments()) { // 如果返回true,表示需要调料this.addCondiments();}
};
var Coffee = function () {};
Coffee.prototype = new Beverage();
// 重写父类方法
Coffee.prototype.brew = function () {console.log("用沸水冲泡咖啡");
};
Coffee.prototype.pourInCup = function () {console.log("把咖啡倒进杯子");
};
Coffee.prototype.addCondiments = function () {console.log("加糖和牛奶");
};
Coffee.prototype.customerWantsCondiments = function () {return window.confirm("请问需要调料吗?");
};
var Coffee = new Coffee();
Coffee.init();

4 好莱坞原则

JS好莱坞原则的基本思想是,高层组件通过调用底层组件暴露的接口来控制底层组件的行为,而底层组件不应该直接依赖或调用高层组件的实现。

这个原则的名字来源于好莱坞电影制片厂,因为在好莱坞电影中,明星演员通常是高层组件,而服装、化妆等其他组件则是底层组件。这些底层组件在电影制作过程中由高层组件来控制和协调。

在这一原则的指导下,我们允许底层组件将自己挂钩到高层组件中,而高层组件会决定什么时候、以何种方式去使用这些底层组件。

模板方法模式是好莱坞原则的一个典型使用场景,它与好莱坞原则的联系非常明显,当我们用模板方法模式编写一个程序时,就意味着子类放弃了对自己的控制权,而是改为父类通知子类,哪些方法应该在什么时候被调用。作为子类,只负责提供一些设计上的细节。

在好莱坞原则的指导之下,下面这段代码可以达到和继承一样的效果。

var Beverage = function (param) {var boilWater = function () {console.log("把水煮沸");};var brew = param.brew; // 冲泡动作var pourInCup = param.pourInCup; // 倒入杯子var addCondiments = param.addCondiments; // 添加调料var F = function () {};F.prototype.init = function () {boilWater();brew();pourInCup();addCondiments();};return F;
};var Coffee = Beverage({brew: function () {console.log("用沸水冲泡咖啡");},pourInCup: function () {console.log("把咖啡倒进杯子");},addCondiments: function () {console.log("加糖和牛奶");},
});var Tea = Beverage({brew: function () {console.log("用沸水浸泡茶叶");},pourInCup: function () {console.log("把茶倒进杯子");},addCondiments: function () {console.log("加柠檬");},
});var coffee = new Coffee();
coffee.init();
var tea = new Tea();
tea.init();

在这段代码中,我们把brewpourInCupaddCondiments这些方法依次传入Beverage函数,Beverage函数被调用之后返回构造器FF类中包含了“模板方法”F.prototype.init。跟继承得到的效果一样,该“模板方法”里依然封装了饮料子类的算法框架。

更多推荐

JavaScript模板方法模式

本文发布于:2023-11-16 11:17:01,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1620096.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:模板   模式   方法   JavaScript

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!