js设计模式-(命令模式)【18】

命令模式,即将请求于实现解耦并封装成独立对象,从而使不同的请求对客户端的实现参数话。其实这种模式我们在很多时候都会用到,通过下面这个简单的例子来说明。为id为div1和div2的元素添加点击事件,分别执行不同的操作,通常情况下我们的操作方式如下:

document.getElementById('div1').addEventListener('click', function(){
	console.log('天气不错')
})
document.getElementById('div2').addEventListener('click', function(){
	console.log('心情不好')
})

这里我们分别为两个元素绑定了不同的事件,但是类似的操作比较多的时候,我们就可以使用命令模式来解耦代码,方便扩展和维护,操作方式如下:首先创建一个对象,用来存放发送事件,执行事件和命令函数。

var order = {} // 命令对象

发送事件:

order.sendCommond = function (el, fn) {
	document.getElementById(el).addEventListener('click', function(){
		fn && fn()
	})
}

执行事件:

order.events = {
	type1: function() {
		console.log('天气不错')
	},
	type2: function() {
		console.log('心情不好')
	}
}

命令函数:

order.commondObj = function(param) {
	this.sendCommond(param.el, this.events[param.type])
}

我们可以发现,这里的3个操作其实是把事件和事件执行内容做了分离,并且事件并不是直接调用,而是由一个命令函数来操作,当同一类型的操作比较多或者比较频繁的时候就可以通过这种方式来简化操作,在扩展性上便更好一点。我们可以通过下面的方式来为id为div1的元素添加事件,如下:

order.commondObj({
	type: 'type1',
	el: 'div1'
})

我们再来看一个另一个场景,很多时候我们会把页面中的文字通过canvas来绘制并以图片的形式来下载,代码如下:

var canvas=document.getElementById('myCanvas');
var ctx=canvas.getContext('2d');
ctx.fillStyle='red';
ctx.fillRect(0,0,80,100);
ctx.fillStyle='green';
ctx.fillRect(10,10,80,100);

这里创建了2个方块,一个红色,一个绿色。这里有一个问题,就是我们每次都需要操作ctx这个canvas的对象,如果代码量大,其实我们更希望把这个元素内置化。其次这种频繁的操作我们更喜欢把它用一个函数来创建,如下:

function creatRect (param) {
        ctx.fillStyle=param.color;
        ctx.fillRect.apply(ctx, param.info);
}
creatRect({
        color: 'red',
        info: [0, 0, 80, 100]
})

我们可以使用命令模式来操作一下,看看怎么把ctx内置,代码如下:

var CanvasCommond = (function() {
	var canvas=document.getElementById('myCanvas');
	var ctx=canvas.getContext('2d');
	var events = {
		setColor: function (color) {
			ctx.fillStyle = color;
		},
		creatRect: function(x, y, width, height) {
			ctx.fillRect(x, y, width, height);
		}
	}
	return {
		excute: function(msg) {
			msg.param = Array.isArray(msg.param) ? msg.param : [msg.param];
			events[msg.commond].apply(events, msg.param);
		}
	}
})();

这里有events和excute两个事件,events是所有的操作集合,excute是命令发起者,我们来调用一下试试:

CanvasCommond.excute({commond: 'setColor', param: 'red'});
CanvasCommond.excute({commond: 'creatRect', param: [40, 40, 80, 100]});

此时页面便出现了一个红色的正方行,当然代码有很多可以优化的地方,不过不是这次的重点。在扩展性上,例如插入图片,画圆角等操作均可以写在event内,传入参数也可以用数组来一次执行。随着画布越来越复杂,这个方式便更加会有用。通过上面两个例子,不难发现,命令模式实现了解耦,也更适用于稍微复杂的逻辑。在逻辑比较简单的情况下,面向过程会显的更加灵活和便于理解。

地址:https://zhuanlan.zhihu.com/p/62413610

发表评论