zoukankan      html  css  js  c++  java
  • 《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     };
  • 相关阅读:
    js获取base64格式图片预览上传并用php保存到本地服务器指定文件夹
    matplotlib等值线显示
    Matplotlib调用imshow()函数绘制热图
    tensorflow 卷积神经网络预测手写 数字
    tensorflow 参数初始化
    matplotlib 读取图形数据
    tensorflow载入数据的三种方式
    tf.get_variable函数的使用
    TF-卷积函数 tf.nn.conv2d 介绍
    Git 常用命令
  • 原文地址:https://www.cnblogs.com/grey-zhou/p/6373390.html
Copyright © 2011-2022 走看看