《javascript设计模式与开发实践》阅读笔记(11)—— 模板方法模式

模板方法模式:

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

 

泡咖啡和泡茶的例子

 

 1     var Coffee = function(){};    //作为构造函数
 2     Coffee.prototype.boilWater = function(){
 3         console.log( '把水煮沸' );
 4     };
 5     Coffee.prototype.brewCoffeeGriends = function(){
 6         console.log( '用沸水冲泡咖啡' );
 7     };
 8     Coffee.prototype.pourInCup = function(){
 9         console.log( '把咖啡倒进杯子' );
10     };
11     Coffee.prototype.addSugarAndMilk = function(){
12         console.log( '加糖和牛奶' );
13     };
14 
15     Coffee.prototype.init = function(){
16         this.boilWater();             //煮水
17         this.brewCoffeeGriends();     //泡咖啡
18         this.pourInCup();             //倒进杯子
19         this.addSugarAndMilk();       //加糖和牛奶
20     };
21 
22     var coffee = new Coffee();   //实例一个“咖啡”对象
23     coffee.init();   //调用
24 
25 
26     var Tea = function(){};    //作为构造函数
27     Tea.prototype.boilWater = function(){
28         console.log( '把水煮沸' );
29     };
30     Tea.prototype.steepTeaBag = function(){
31         console.log( '用沸水浸泡茶叶' );
32     };
33     Tea.prototype.pourInCup = function(){
34         console.log( '把茶水倒进杯子' );
35     };
36     Tea.prototype.addLemon = function(){
37         console.log( '加柠檬' );
38     };
39 
40     Tea.prototype.init = function(){
41         this.boilWater();      //煮水
42         this.steepTeaBag();    //泡茶
43         this.pourInCup();      //倒进杯子
44         this.addLemon();       //加柠檬
45     };
46 
47     var tea = new Tea();  //实例一个“茶”对象
48     tea.init();    //调用

 

 

观察两段代码,发现其实他们是大同小异的,那我们完全可以把公共的部分抽象出来,作为一个抽象的父类模板

 

 1     var drink=function(){}  //作为抽象的构造类
 2     drink.prototype.boilWater=function(){
 3         console.log( '把水煮沸' );
 4     }
 5     drink.prototype.brew=function(){};  //空方法,用来给模板套用
 6     drink.prototype.pourInCup = function(){};   // 同上  
 7     drink.prototype.addCondiments = function(){}; //  同上
 8 
 9     drink.prototype.init = function(){    //模板在这里,重复的事情放在模板里
10         this.boilWater();
11         this.brew();
12         this.pourInCup();
13         this.addCondiments();
14     };

 

然后就是具体的咖啡类和茶类

 1     /**创建咖啡类**/
 2     var Coffee = function(){};    //这是一个具体的类,作为构造函数存在
 3     Coffee.prototype = new drink();   //把构造函数的prototype指向抽象类的实例
 4 
 5     Coffee.prototype.brew = function(){
 6         console.log( '用沸水冲泡咖啡' );
 7     };
 8     Coffee.prototype.pourInCup = function(){
 9         console.log( '把咖啡倒进杯子' );
10     };
11     Coffee.prototype.addCondiments = function(){
12         console.log( '加糖和牛奶' );
13     };
14 
15     var coffee = new Coffee();  //新建咖啡实例
16     coffee.init();            //调用模板
17     /*结果*/
18     //把水煮沸
19     //用沸水冲泡咖啡
20     //把咖啡倒进杯子
21     //加糖和牛奶
 1     /**创建茶类**/
 2     var Tea = function(){};       //具体的类,作为构造函数
 3     Tea.prototype = new drink();  //把构造函数的prototype指向抽象类的实例
 4 
 5     Tea.prototype.brew = function(){
 6         console.log( '用沸水浸泡茶叶' );
 7     };
 8     Tea.prototype.pourInCup = function(){
 9         console.log( '把茶倒进杯子' );
10     };
11     Tea.prototype.addCondiments = function(){
12         console.log( '加柠檬' );
13     };
14 
15     var tea = new Tea();   //新建茶实例
16     tea.init();     //调用模板
17     /*结果*/
18     //把水煮沸
19     //用沸水浸泡茶叶
20     //把茶倒进杯子
21     //加柠檬

 

使用es6的话,代码可以简洁不少

 1      class drink{    //抽象模板父类
 2         boilWater(){
 3            console.log("把水煮沸");
 4         };
 5         brew(){};
 6         pourInCup(){};
 7         addCondiments(){};
 8 
 9         init(){
10            this.boilWater();
11            this.brew();
12            this.pourInCup();
13            this.addCondiments();
14         }
15      }
16 
17      class Coffee extends drink{  //具体的类,内部重写相应方法
18         brew(){
19            console.log("用沸水冲泡咖啡");
20         }
21         pourInCup(){
22            console.log( '把咖啡倒进杯子' );
23         }
24         addCondiments(){
25            console.log( '加糖和牛奶' );
26         }
27      }
28 
29      var coffee=new Coffee(); //实例
30      coffee.init();   //把水煮沸
31                       //用沸水冲泡咖啡
32                       //把咖啡倒进杯子
33                       //加糖和牛奶

 

 

js实现模板模式的一些问题

我们在抽象父类中提供了模板,在具体的类中重写相应的方法,但是这个过程全靠程序员的自觉和记忆,语言层面并没有提供任何检查,如果我们忘了重写相应的方法,js也不会报错。
一种解决方案是用鸭子类型来模拟接口检查,缺点就是会带来很多不必要的复杂性,增加很多和业务无关的代码。
另一种解决方案是抽象父类中的相应抽象方法里都抛出错误,如果子类没有重写相应方法,运行时就会报错,如下:

1     drink.prototype.brew=function(){
2         throw new Error( '子类必须重写brew 方法' );
3     };

 

钩子方法

可以增加自由度,有的子类并不适合把模板方法全部运行,钩子方法可以让子类自行决定是否执行对应的模板方法。

 1     drink.prototype.add=function(){  //钩子方法,子类中可以改写,模板方法中会进行判断
 2         return true;   //默认为true,用于判断
 3     }
 4     drink.prototype.init = function(){  //模板方法  
 5         this.boilWater();
 6         this.brew();
 7         this.pourInCup();
 8         if( this.add() ){   //如果挂钩返回true,则需要调料
 9             this.addCondiments();
10         }
11     };

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值