您的位置:首页 > Web前端 > JavaScript

组合模式

2015-10-18 19:56 543 查看
组合模式大概是设计模式里面使用最为广泛的模式之一了,模式本身理解起来也比较简单,以至于可以毫不费力的写出一个能用的组合模式伪代码。

该模式解决了什么问题?

组合模式统一对待复合对象与单个对象。抽象出统一的命令执行接口,这种
多态性
使得客户端在编写代码的时候可以不加区分当前要操作的是复合对象还是单个对象。

组合模式基本实现

function inherits(child, sup) {
child.prototype = Object.create(sup.prototype, {
constructor: {
value: child,
enumerable: false,
configurable: true,
writable: true
}
});
}
//组合对象与叶子对象都集成自component对象
function Component() {

}

Component.prototype.execute = function(context) {
throw new Error('Component function must be override');
};

Component.prototype.add = function(command) {
throw new Error('Component function must be override');
};

Component.prototype.remove = function(command) {
throw new Error('Component function must be override');
};

function Composite() {
this.childs = [];
Component.call(this);
}

inherits(Composite, Component);

Composite.prototype.execute = function(context) {
for(var i = 0; i < this.childs.length; i++) {
this.childs[i].execute(context);
}
};

Composite.prototype.add = function(child) {
this.childs.push(child);
};

Composite.prototype.remove = function(child) {
for(var i = 0; i < this.childs.length; i++) {
if(child == this.childs[i]) {
this.childs.splice(i, 1);
}
}
};
//叶子节点不能添加子对象
function Leaf(command) {
Component.call(this);
this.command = command;
}

inherits(Leaf, Component);

Leaf.prototype.execute = function(context) {
if(!this.command) return;
this.command.execute(context);
};


以上是传统面向对象语言对于组合模式的一个规范实现,由于Javascript这种动态语言本身的一些限制,我们通过在
基类
抛出异常的方式来阻止客户端往
Leaf
对象中添加子对象,代码整体来看会有一些冗余,下面来写一个简单的实现。

Javascript下的实现

组合模式无非就是需要一个列表来存放子对象,这些对象往往是一些需要被执行的命令(
常和命令模式组合运用
)。所以我们可以写成如下形式:

var CompositeCommand = function() {
return {
commandList: [],
add: function(command) {
this.commandList.push(command);
},
execute: function(context) {
for(var i = 0, length = this.commandList.length; i < length; i++) {
var command = this.commandList[i];
command.execute(context);
}
}
};
}

var openWindowCommand = {
execute: function(ctx) {
console.log('openWindowCommand');
}
};

var playMusicCommand = {
execute: function(ctx) {
console.log('playMusicCommand');
}
};

var closeDoorCommand = {
execute: function(ctx) {
console.log('closeDoorCommand');
}
};

var composite1 = CompositeCommand();
composite1.add(playMusicCommand);
composite1.add(openWindowCommand);
var composite = CompositeCommand();
composite.add(composite1);
composite.add(closeDoorCommand);
composite.execute();


输出:

playMusicCommand
openWindowCommand
closeDoorCommand


组合模式常用的一般情况

组合模式适用于对一组对象执行同一类操作,而这组对象有可能是包含关系,也可以是单个个体。常用的情形如:文件扫描,我们扫描文件的时候并不关心当前是文件夹或者是单个文件,都可以统一执行
scan
接口,当然前提是我们已经得到了一组文件对象的依赖关系。再如,GUI绘制界面的时候,通常会先绘制主窗口渲染背景,然后再绘制叠加在窗口上的各个子控件,而这些子控件有可能又包含一些子控件。基于GUI控件的依赖层次关系。也非常适合使用组合模式:

var createDialog = function () {
return {
bgimg: 'blues.png',
children: [],
addChild: function(child) {
this.children.push(child);
},
paintSelf: function(context) {
console.log('paint dialog');
},
paint: function(context) {
this.paintSelf(context);
for(var i = 0, length = this.children.length; i< length; i++) {
var child = this.children[i];
child.paint(context);
}
}
};
}

var createButton = function() {
return {
paint: function(ctx) {
console.log('paint button');
}
};
};

var createListView = function() {
return {
children: [],
addChild: function(item) {
this.children.push(item);
},
paint: function(ctx) {
console.log('paint listview');
for(var i = 0; i < this.children.length; i++) {
this.children[i].paint(ctx);
}
}
};
};

var createListItem = function() {
return {
paint: function(ctx) {
console.log('paint list item');
}
};
};

var window = createDialog();
var dialog1 = createDialog();
dialog1.addChild(createButton());
window.addChild(dialog1);
var dialog2 = createDialog();
var listview = createListView();
listview.addChild(createListItem());
dialog2.addChild(listview);
window.addChild(dialog2);

window.paint({});


输出

paint dialog
paint dialog
paint button
paint dialog
paint listview
paint list item


后记

1.复合对象与单个对象不是父子关系,二是聚合(has-A)关系。

2.节点必须有统一的操作接口
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  设计模式 javascript