14-JavaScript设计模式——组合模式

组合模式:用于处理一批具有树形结构的对象的模式。

如:

-> 公司

-> 财务部门

-> 张一

-> 张二

-> 张三

-> 销售部门

-> 张四

-> 张五

-> 张六

对于以上的树形结构,我们要对这批对象或其中一部分对象实施一个操作,可以不采用设计模式来完成,但是存在一个问题,假如需求发生变化,需要增加一个新的层级结构,那么程序的可维护性和可扩展性会很差,那么我们可以用组合模式来解决这个问题。


观察以上的树形结构,是不是和文件目录结构很像?在文件目录结构中,只存在两种对象:文件夹和文件。那么“公司”和“部门”其实都相当于文件夹,张一、张二 等相当于文件,组合模式就是利用这一特点来处理树形结构的。


组合模式的特点:

1、组合模式中只有两种类型的对象:组合对象(文件夹)、叶子对象(文件);

2、这两种类型都实现同一批接口;

3、一般我们会在组合对象中调用其方法并隐式的调用“下级对象”的方法(一般采用 递归)


// 建立接口
var CompositeInterface = new JG.Interface('CompositeInterface', ['addChild', 'getChild']);
var LeafInterface = new JG.Interface('LeafInterface', ['hardworking', 'sleeping']);

// 组合对象
var Composite = function(name){
	this.name = name;
	this.type = 'Composite';
	this.children = [];
};

Composite.prototype = {
	constructor : Composite,
	addChild : function(child){
		this.children.push(child);
		return this; // 链式编程
	},
	getChild : function(name){
		// 这个方法是关键

		// 接收叶子对象的数组
		var elements = [];

		var pushLeaf = function(item){
			if (item.type === 'Composite') {
				item.children.forEach(arguments.callee);
			}else if (item.type === 'Leaf') {
				elements.push(item);
			}
		}

		if (name && this.name !== name) {
			this.children.forEach(function(item){
				if (item.name === name && item.type === 'Composite') {
					item.children.forEach(pushLeaf);
				}
				if (item.name !== name && item.type === 'Composite') {
					item.children.forEach(arguments.callee);
				}
				if (item.name === name && item.type === 'Leaf') {
					elements.push(item);
				}
			});
		}else{// 如果没有传递name,则获得所有的Leaf(叶子类型)对象
			this.children.forEach(pushLeaf);
		}

		return elements;
	},
	hardworking : function(name){
		// 得到所有的Leaf(叶子类型)对象
		var childObjects = this.getChild(name);
		for (var i = 0; i < childObjects.length; i++) {
			childObjects[i].hardworking();
		}
	},
	sleeping : function(name){
		// 得到所有的Leaf(叶子类型)对象
		var childObjects = this.getChild(name);
		for (var i = 0; i < childObjects.length; i++) {
			childObjects[i].sleeping();
		}
	}
};

// 叶子对象
var Leaf = function(name){
	this.name = name;
	this.type = 'Leaf';
};

Leaf.prototype = {
	constructor : Leaf,
	addChild : function(child){
		throw new Error('the final child addChild method is disabled...');
	},
	getChild : function(name){
		if (this.name === name) {
			return this;
		}
		return null;
	},
	hardworking : function(name){
		document.write(this.name + '...努力工作!<br>');
	},
	sleeping : function(name){
		document.write(this.name + '...努力睡觉!<br>');
	}
};

// 测试
// 创建一批叶子对象
var z1 = new Leaf('张一');
var z2 = new Leaf('张二');
var z3 = new Leaf('张三');
var z4 = new Leaf('张四');
var z5 = new Leaf('张五');
var z6 = new Leaf('张六');

// 创建组合对象(部门)
var dept1 = new Composite('财务部门');
var dept2 = new Composite('销售部门');

// 为部门添加员工
dept1.addChild(z1).addChild(z2).addChild(z3);
dept2.addChild(z4).addChild(z5).addChild(z6);

// 创建组合对象(公司)
var org = new Composite('中国有限公司');

// 为公司添加部门
org.addChild(dept1).addChild(dept2);

// 获得全部员工
var arr = org.getChild();
arr.forEach(function(item){
  document.write(item.name + '<br>');
});
/*
	结果:
		张一
		张二
		张三
		张四
		张五
		张六

*/

// 让销售部门的所有员工努力工作
org.hardworking('销售部门');
/*
	结果:
		张四...努力工作!
		张五...努力工作!
		张六...努力工作!
*/

// 让财务部门的所有员工努力睡觉
org.sleeping('财务部门');
/*
	结果:
		张一...努力睡觉!
		张二...努力睡觉!
		张三...努力睡觉!
*/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值