命令模式(Command)
将请求与实现解耦并封装成独立对象,从而使不同的请求对客户端的实现参数化。
自由化创建视图命令
<style>
#title-box .title .main h2{
text-align: center;
}
#title-box .title .main p{
text-align: right;
}
#picture-box {
text-align: center;
}
#picture-box .picture{
position: relative;
display: inline-block;
margin: 10px;
border: 1px solid #333;
}
#picture-box .picture p{
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 30px;
line-height: 30px;
text-align: center;
margin: 0;
background-color: rgba(0, 0, 0, .5);
color: #fff;
}
</style>
<body>
<div id="title-box"></div>
<div id="picture-box"></div>
</body>
// 模块实现模块
var viewCommand = (function () {
// 模板
let tpl = {
// 标题结构模板
title:
`<div class="title">
<div class="main">
<h2>{#title#}</h2>
<p>{#tips#}</p>
</div>
</div>`,
// 图片结构模板
picture:
`<div class="picture">
<img src="{#src#}"/>
<p>{#text#}</p>
</div>`,
};
// 存储经过格式化最终返回的html
let html = '';
/**
* 格式化字符串将
* @param {string} str 原字符串
* @param {object} obj 模板数据
* @returns 最终解析好的html字符串
*/
function formateString(str, data) {
return str.replace(/\{#(\w+)#\}/g, function (_match, key) {
return data[key];
})
}
// html = formateString(tpl.title, {title: 'You瞧谁不起 - 道不尽世间的沧桑,诉不完人生的悲凉', tips: '人海茫茫,你我依旧孤独~~~'});
// document.body.innerHTML = html;
// console.log(html);
// 定义指令
let Action = {
/**
* 解析数据方法html变量中
* @param {string} view 模板视图
* @param {object} data 数据
*/
create(view, data) {
// 针对数组的模板解析d
if (Array.isArray(data)) {
data.forEach(d => {
html += formateString(tpl[view], d);
})
}
// 针对对象的模板解析
else {
html += formateString(tpl[view], data);
}
},
/**
* 展示html到指定容器内,如果此时定义了模板数据解析那么追加模板
* @param {string} id DOM ID
* @param {string} view 模板视图(追加)
* @param {object} data 数据
*/
display(id, view, data) {
console.log(id, view, data);
if (data) {
this.create(view, data); // 追加模板
}
console.log(html);
document.getElementById(id).innerHTML = html;
html = ''; // 展示后清空缓存的字符串
}
};
/**
* 命令接口
* @param {object} param
* {
* @param {Array} params 数组参数 create->[view, data] display->[id, view, data]
* @param {string} command 指令-create/display
* }
*/
return function excute({
params, command }) {
// 将参数转转换未数组
params = Array.isArray(params) ? params : [params];
// 执行指令
Action[command].apply(Action, params);
}
})();
const objData = {
title: 'You瞧谁不起 - 道不尽世间的沧桑,诉不完人生的悲凉',
tips: '人海茫茫,你我依旧孤独~~~'
};
// 渲染标题模块DOM
viewCommand({
command: 'display',
params: ['title-box', 'title', objData]
});
const listData1 = [
{
text: '图片01', src: 'https://dummyimage.com/200x100/ff0/fff' },
{
text: '图片02', src: 'https://dummyimage.com/200x100/0ff/fff' },
{
text: '图片03', src: 'https://dummyimage.com/200x100/0f0/fff' },
];
const listData2 = [
{
text: '图片04', src: 'https://dummyimage.com/200x100/f0f/fff' },
{
text: '图片05', src: 'https://dummyimage.com/200x100/00f/fff' },
{
text: '图片06', src: 'https://dummyimage.com/200x100/f00/fff' },
];
// 暂存使用listData1解析 出来的html字符串
viewCommand({
command: 'create',
params: ['picture', listData1]
});
// 渲染 暂存的 和 使用listData2解析 出来的html字符串
viewCommand({
command: 'display',
params: ['picture-box', 'picture', listData2]
});
绘图命令
// 绘图指令
var CanvasCommand = (function () {
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 指令方法
var Action = {
/**
* 填充色彩
* @param {string} c 颜色
*/
fillStyle(c) {
ctx.fillStyle = c;
},
/**
* 填充矩形
* @param {number} x 位置x
* @param {number} y 位置y
* @param {number} w 矩形宽度
* @param {number} h 矩形高度
*/
fillRect(x, y, w, h) {
ctx.fillRect(x, y, w, h);
},
/**
* 描边色彩
* @param {string} c 颜色
*/
strokeStyle(c) {
ctx.strokeStyle = c;
},
/**
* 描边矩形
* @param {number} x 位置x
* @param {number} y 位置y
* @param {number} w 矩形宽度
* @param {number} h 矩形高度
*/
strokeRect(x, y, width, height) {
ctx.strokeRect(x, y, width, height);
},
/** ...CODE... */
};
// 命令接口
return function (data) {
data = Array.isArray(data) ? data : [data];
data.forEach(d => {
let params = Array.isArray(d.params) ? d.params : [d.params];
Action[d.command].apply(Action, params);
})
}
})();
// 执行多个指令
CanvasCommand([
{
command: 'fillStyle', params: 'red' },
{
command: 'fillRect', params: [20, 20, 100, 100] }
]);
// 执行单个指令
CanvasCommand({
command: 'fillRect',
params: [150, 20, 50, 50],
});
特点:
不用关心每种方法的具体实现了,即使在不同浏览器实现不一致我们也不用关心,因为那些不兼容的问题都已经在命令对象内部实现了
命令模式
是将执行的命令封装
,解决命令的发起者
与命令的执行者
之间的耦合
。
每条命令
实质上是一个操作
。命令的使用者
不必了解
命令的执行者(命令对象)的命令接口
是如何实现的、命令是如何接受的、命令是如何执行
的。所有的命令
都被存储在命令对象中
。
优点
:- 解决命令使用者之间的耦合;
- 新的命令很容易加入到命令系统中,供使用者使用;
- 命令的使用具有一致性,多数的命令在一定程度上是简化操作方法的使用的;
缺点
:- 命令模式是对一些操作的封装,这就造成每执行一次操作都要调用一次命令对象,增加了系统的复杂度;