《javascript设计模式与开发实践》读书笔记(5)
本周分享的是命令模式和组合模式。
命令模式
命令模式的意义在于将一个操作封装在一个命令对象中,从而将其四处传递。而JavaScript是将函数作为一等对象的语言,函数本身就可以四处传递,因此命令模式在JavaScript是天然实现的。但是就算这样,命令模式在JavaScript中仍然有期重要的意义,我们通过将某些操作封装在命令对象中,可以记录所有的历史操作,从而方便我们撤销重做**。下面我们看一个例子,我们实现一个canvas画线的功能,要求能撤销本次操作,并重复撤销的操作。canvas并不能删除元素,那canvas如何实现撤销的命令。其实我们可以记录,每次划线的参数,当需要撤销的时候,我们就清空画布,然后执行画线的的操作,直到当前操作之前。下面我们看代码,
var drawLineCommand = (function () { var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var drawer = {}; drawer.drawLine = function (config) { ctx.beginPath(); ctx.moveTo.apply(ctx, config.startPoint); ctx.lineTo.apply(ctx, config.endPoint); ctx.stroke(); }; function DrawLineCommand(reciver) { this.reciver = reciver; this.historyCommands = []; this.currentStep = 0; } DrawLineCommand.prototype.excute = function (config) { this.historyCommands.push(config); this.reciver.drawLine(config); this.currentStep = this.historyCommands.length - 1; }; DrawLineCommand.prototype.undo = function () { ctx.clearRect(0, 0, canvas.width, canvas.height); var currentStep = this.currentStep; for (var i = 0; i < currentStep; i++) { this.excute(this.historyCommands[i]); } this.currentStep = currentStep - 1; }; DrawLineCommand.prototype.redo = function () { var config = this.historyCommands[this.currentStep + 1]; if (config) { this.excute(this.historyCommands[this.currentStep + 1]); this.currentStep++; } }; return new DrawLineCommand(drawer); })() var config1 = { startPoint: [100, 100], endPoint: [200, 200] }; var config2 = { startPoint: [200, 200], endPoint: [300, 200] }; drawLineCommand.excute(config1); drawLineCommand.excute(config2); drawLineCommand.undo(); drawLineCommand.redo();
组合模式
组合模式将对像组成树形结构,组合模式的命令可以递归的执行下去。现在考虑这样的一个场景,我们用js定义了一个组件,这个组件有个render函数,通过render函数,这个组件就可以渲染在某个DOM元素上,同时这个组件还可以接受其它的一些组件,这些组件也有一个render函数。这样我们就可以得到一个组件树,当我们调用根组件的render函数的时候,整个组件树就会递归的调用render函数,直到整个树渲染出来。
(function () { function CircleComponent (config) { this.element = document.createElement('div'); this.element.style.width = 2 * parseInt(config.radius, 10) + 'px'; this.element.style.height = 2 * parseInt(config.radius, 10) + 'px'; this.element.style.borderRadius = config.radius; this.element.style.backgroundColor = config.color; } CircleComponent.prototype.render = function (parent) { parent.appendChild(this.element); } function CirclesComponent (config) { this.element = document.createElement('div'); console.log(this.element); this.children = []; for (var i = 0; i < config.number; i++) { j = i % config.radius.length; k = i % config.color.length; var secondConfig = { color: config.color[k], radius: config.radius[j] } this.children.push(new CircleComponent(secondConfig)); } } CirclesComponent.prototype.render = function (parent) { var element = this.element; this.children.forEach(function(item) { item.render(element); }); parent.appendChild(this.element); } var config = { number: 3, radius: ['100px'], color: ['#f00', '#0f0', '#0ff'] }; var circles = new CirclesComponent(config); circles.render(document.getElementById('circles')); })()#笔记##读书笔记##设计#