模板方法模式

JavaScript-模板方法模式

模板方法是什么鬼?模板模式又是什么鬼?😩 听说它很复杂,听说它很难,我可不可以不学啊😭。刷了一会儿微博,这几天杨洋的新电影《三生三世十里桃花》上映了,不行,我要去看,虽然闺蜜说不好看,但是,去看杨洋也是可以的,嘻嘻嘻。 嗯,模板模式应该是跟杨洋一样帅,所以带着这份爱慕,我们一起来看看它到底有没有比杨洋还要帅!!

1.jpg

模板方法模式是什么?

模板方法模式是一种只需使用继承就可以实现的非常简单的模式。这是它的一种定义,简单吗?不觉得。😔

说到继承,我们一定会能够想到它肯定有父亲,不然要怎么继承。模板方法模式由两部分结构组成,第一部分是抽象父类,第二部分是具体实现的子类。完了,又出来一个概念,抽象类?别怕,我们一一来讲解。在模板方法模式中,子类实现中的相同部分被上移到父类中,而将不同的部分留给子类来实现。

完了,一不小心扔了这么多概念,你肯定晕了,不怕,不怕,上实例了哈。😊

先泡一杯咖啡吧!

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

1.先把水煮沸;

2.用沸水冲泡咖啡;

3.把咖啡倒进杯子;

4.加糖和牛奶。

我们用es5来得到一杯香浓的咖啡吧:

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();

如我们所愿了,控制台会输出泡茶的流程,和我们写下的一样。

我想喝茶吖,想喝茶。不急,不急,我们再来泡茶哈!
3.jpg

泡一壶茶啦!

其实呢,泡茶的步骤跟泡咖啡的步骤相差不大,大致是这样的:

1.把水煮沸;

2.用沸水浸泡茶叶;

3.把茶水倒进杯子;

4.加柠檬。

来,咱用es6来泡茶:

class Tea{
    constructor(){

    }
    boilWater(){
        console.log('把水烧开');
    }
    steepTeaBag(){
        console.log('浸泡茶叶');
    }
    pourInCup(){
        console.log('倒进杯子');
    }
    addLemon(){
        console.log('加柠檬');
    }
    init(){
            this.boilWater();
            this.steepTeaBag();
            this.pourInCup();
            this.addLemon();
    }
}
var tea=new Tea();
tea.init();

又如我们所愿了,控制台输出了泡茶的流程。

思考啦!

现在到了思考的时间,我们刚刚泡了一杯咖啡和一壶茶,有没有觉得这两个过程是大同小异的。我们能很容易的就找出他们的共同点,不同点就是原料不同嘛,茶和咖啡,我们可以把他们抽象为"饮料"哇;泡的方式不同嘛,一个是冲泡,一个是浸泡,我们可以把这个行为抽象为"泡";加入的调料也不同咯,加糖和牛奶,加柠檬,它们也可以抽象为"调料"吖。

这么一分析,是不是很清楚了吖,我们整理一下就是:

1.把水煮沸;

2.用沸水冲泡饮料;

3.把饮料倒进杯子;

4.加调料。

大家请注意!大家请注意!主角来了!之前我们已经扔出了概念,所以我们现在可以创建一个抽象父类来表示泡一杯饮料的过程。那么,抽象父类?

抽象类?

抽象类是不能被实例化的,一定是用来继承的。继承了抽象类的所有子类都将拥有跟抽象类一致的接口方法,抽象类的主要作用就是为它的子类定义这些公共接口。

通过上面分析,这里具体来说就是要把泡茶和泡咖啡的共同步骤共同点找出来,封装到父类,也就是抽象类中,然后不同的步骤写在子类中,也就是茶和咖啡中。抽象类既然不能被实例化,不怕啊,子类就是他的实例化。

来吧!泡饮料啦!

var Beverage=function(){}
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(){
    // 将父类的构造方法拿来执行一下
    Beverage.apply(this,arguments);
    // 就像es6的super执行 执行后this才会有对象的属性
}
Coffee.prototype=new Beverage();
var coffee=new Coffee();
coffee.init();
var Tea=function(){

}
Tea.prototype=new Beverage();
Tea.prototype.brew=function(){
    console.log('用沸水浸泡茶叶');
}
Tea.prototype.pourInCup=function(){
    console.log('把茶叶倒进杯子');
}
Tea.prototype.addCondiments=function(){
    console.log('加柠檬');
}
var tea=new Tea();
tea.init();

这里既泡了咖啡又泡了茶,是不是没有之前那么繁琐呢,这里的代码可是很高级的呢。

这里用一个父类Beverage来表示Coffee和Tea,然后子类就是后面的Coffee和Tea啦,因为这里的Beverage是一个抽象的存在,需要子类来继承它。泡饮品的流程,可以理解为一个模板模式 ,抽象类Beverage, 抽象方法init()在子类中实现。js的继承是基于原型链的继承,这里prototype就是类的原型链。这里由于coffee对象和tea对象的原型prototype上都没有对应的init(),所以请求会顺着原型链,找到父类Beverage的init()。子类寻找对应的属性和方法的时候会顺着原型链去查找,先找自己,没有找到会顺着去父类里面查找。

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

闭包实现模板方法模式

闭包也可以实现的哟,大家对闭包不太理解的可以参考我之前的文章:作用域闭包

var Beverage=function(param){
    // 局部变量
    var boilWater=function(){
       console.log('把水煮沸');
    }
    // 配置
    var brew=param.brew||function(){
        throw new Error('必须传递brew方法');
    }
    var pourInCup=param.pourInCup||function(){
        throw new Error('必须传递pourInCup方法')
    }
    var addCondiments=param.addCondiments||function(){
        throw new Error('必须传递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 coffee=new Coffee(); 
coffee.init();

js 把抽象类改为配置类,param将成为Beverage函数里面的闭包函数的引用。Beverage是模板,把他变成一个可以配置的类把参数param传进来,就玩成了配置。这里的配置就是给Beverage传参数,也就是param。F对象规范了类的构成(流程), 里面的四个私有变量是闭包的。当Beverage new 的时候会new 一个F, 然后就调用了闭包 ,四个私有变量也被调用。

父类里面的brew pourInCup addCondiments方法都是空的,所以子类必须重写。父类里面的那三个方法是如果子类没用重写该方法,就会直接抛出一个异常那个,程序在运行时会得到一个错误。

小结

模板方法模式时一种典型的通过封装变化提高系统扩展性的设计模式。运用了模板方法模式的程序中,子类方法种类和执行顺序都是不变的,但是子类的方法具体实现则是可变的。父类是个模板,子类可以添加,就增加了不同的功能。子类和父类之间也就是"尧舜禹"之间的关系,属于同一类,没有血缘关系。

哇,到这里帅哥就看完啦,是不是很帅,是不是很有意思,不行,我要去看我的杨洋了,抛弃我的杨洋。😄

2.jpg

有建议或者觉得有错误的地方可以指出来哟,帅哥要分享,学习也要分享的。共同进步吧!😘

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容