乐趣区

js设计模式–模板方法模式

前言
本系列文章主要根据《JavaScript 设计模式与开发实践》整理而来,其中会加入了一些自己的思考。希望对大家有所帮助。
文章系列
js 设计模式 – 单例模式
js 设计模式 – 策略模式
js 设计模式 – 代理模式
js 设计模式 – 迭代器模式
js 设计模式 – 发布订阅模式
js 设计模式 – 命令模式
js 设计模式 – 组合模式
概念
模板方法模式是一种只需使用继承就可以实现的非常简单的模式。模板方法模式由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。通常 在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。
场景
一般用于可以抽取公共方法,例如泡咖啡和泡茶,我们可以抽取烧水 清洗杯具 冲泡等过程
优缺点
优点
可以复用公共方法,子类也不需要实现算法部分
例子
模板引擎
我们实现一个简单的模板引擎:

<!DOCTYPE html>
<html lang=”en”>

<head>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
<meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
<title>Document</title>
</head>

<body>
<div id=”nav”></div>
<script>
var formateStr = function (param, data) {
return param.replace(/\{#(\w+)#\}/g, function (match, key) {
return typeof data[key] === undefined ? “” : data[key];
});
};

var Nav = function (data) {
var _this = this;
_this.item = ‘<li><a href=”{#hrefUrl#}” title=”{#title#}” {#sign#}>{#content#}</a></li>’;
_this.html = ‘<ul>’;
for (var i = 0, l = data.length; i < l; i++) {
_this.html += formateStr(_this.item, data[i]);
}
_this.html += ‘</ul>’;
return _this.html;
}

var objNav = document.getElementById(‘nav’);
objNav.innerHTML = Nav([{
hrefUrl: ‘http://www.baidu.com’,
content: ‘ 百度一下 ’
},
{
hrefUrl: ‘http://www.zhihu.com’,
content: ‘ 知乎一下 ’
}
]);
</script>
</body>

</html>

现在产品加了一个需求,想在 content 后面加个 span 标签展示访问次数
新需求
普通程序员就会动手去改 Nav 方法,但这违背了开放封闭原则,我们也不能确保不影响原来的功能,其实我们加多一个模板方法就可以规避这样的问题

<!DOCTYPE html>
<html lang=”en”>

<head>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
<meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
<title>Document</title>
</head>

<body>
<div id=”nav”></div>
<script>
var formateStr = function (param, data) {
return param.replace(/\{#(\w+)#\}/g, function (match, key) {
return typeof data[key] === undefined ? “” : data[key];
});
};

var Nav = function (data) {
var _this = this;
_this.item = ‘<li><a href=”{#hrefUrl#}” title=”{#title#}” {#sign#}>{#content#}</a></li>’;
_this.html = ‘<ul>’;
for (var i = 0, l = data.length; i < l; i++) {
_this.html += formateStr(_this.item, data[i]);
}
_this.html += ‘</ul>’;
return _this.html;
}

var infoNav = function (data) {
var _this = this;
_this.info = ‘<span>{#clickNum#}</span>’;
for (var i = data.length – 1; i >= 0; i–) {
data[i].content += formateStr(_this.info, data[i]);
};
return Nav.call(this, data);
};
var objNav = document.getElementById(‘nav’);
objNav.innerHTML = infoNav([{
hrefUrl: ‘http://www.baidu.com’,
content: ‘ 百度一下 ’,
title: ‘ 百度 ’,
clickNum: ’10’,
sign: ‘sign=”1″‘
},
{
hrefUrl: ‘http://www.zhihu.com’,
content: ‘ 知乎一下 ’,
title: ‘ 知乎 ’,
clickNum: ‘100’,
sign: ‘sign=”2″‘
}
]);
</script>
</body>

</html>

退出移动版