组合模式

场景:公司最近接了一个项目,为一家大公司做一个工作管理系统,类似于常见的OA系统,单从需求分析的话,不难开发。但是考虑到大公司希望在所有分公司推广使用,如果采用简单复制同一套代码,效果不如人意,总公司和分公司是成树状结构,也就是有组织结构的,不能是简单的平行管理。有些功能只能总公司使用,而部分功能总公司和分公司可以共同使用,比如人力资源部之类的。这就涉及到整体与部分的关系—整体和部分可以被一致对待的问题!

由此引出新的设计模式

组合模式(Composite):将对象组合成树状结构以表示'部分-整体'的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

组合模式(Composite)结构图


Component为组合中的对象抽象类,在适当情况下,实现所有类的默认方法

package composite;

abstract class Component {
	protected String name;

	public Component(String name) {
		this.name = name;
	}
	
	/**
	 * @param c
	 * 通过用Add和Remove方法来提供增加或移除叶结点或枝结点的功能
	 */
	public abstract void Add(Component c);
	public abstract void Remove(Component c);
	public abstract void Display(int depth);
}

Leaf在组合中表示叶节点对象,叶节点没有子节点

package composite;

public class Leaf extends Component {

	public Leaf(String name) {
		super(name);
	}
	
	/**
	 * 叶节点无法再增加分支和树叶,所以Add和Remove方法的实现没有意义,
	 * 但是这样做可以消除叶结点和枝结点在抽象层次的区别,他们具有完全一致的接口
	 */
	@Override
	public void Add(Component c) {
		System.out.println("Cannot add to a leaf ");
	}

	@Override
	public void Remove(Component c) {
		System.out.println("Cannot remove from a leaf");
	}
	
	/**
	 * @see composite.Component#Display(int)
	 * 叶结点的具体方法,此处是显示其名称和级别的
	 */
	@Override
	public void Display(int depth) {
		System.out.println(new StringBuffer("-").append(depth)+ name);
	}

}
Composite定义枝节点的行为,用来存储子部件
package composite;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Composite extends Component {
	//一个子对象的集合用了存储其下属的枝结点和叶节点
	private List<Component> children = new ArrayList<>();
	public Composite(String name) {
		super(name);
	}

	@Override
	public void Add(Component c) {	//增加下级结点
		children.add(c);
	}

	@Override
	public void Remove(Component c) {	//移除下级结点
		children.remove(c);
	}

	/**
	 * 显示枝结点名称,并对其下级进行遍历
	 */
	@Override
	public void Display(int depth) {
		System.out.println(new StringBuffer("-").append(depth)+name);
		Iterator<Component> iterator = children.iterator();
		while(iterator.hasNext()){
			iterator.next().Display(depth+2);
		}
	}

}

客户端代码,通过Component操作组合部件的对象

package composite;

public class Client {
	public static void main(String[] args) {
		/**
		 * 树根root,其下有两片子叶 A B
		 */
		Composite root = new Composite("root");
		root.Add(new Leaf("Leaf A"));
		root.Add(new Leaf("Leaf B"));
		
		/**
		 * 树根root,长出分支M,分支下有两片子叶 X ,Y
		 */
		Composite M = new Composite("Composite M");
		M.Add(new Leaf("Leaf X") );
		M.Add(new Leaf("Leaf Y") );
		root.Add(M);
		
		/**
		 * 树根root,长出分支N,分支下有两片子叶1 ,2
		 */
		Composite N = new Composite("Composite N");
		N.Add(new Leaf("Leaf 1") );
		N.Add(new Leaf("Leaf 2") );
		root.Add(N);
		
		//显示树的结构
		root.Display(1);
	}
}

结果显示

-1root
-3Leaf A
-3Leaf B
-3Composite M
-5Leaf X
-5Leaf Y
-3Composite N
-5Leaf 1
-5Leaf 2

树有无数的分支,可以通过Composite来实现树状结构,而叶节点Leaf不能再增加分支,所以Componet内声明的Add和Remove方法对于Leaf来讲实现是没有意义的。这种方式叫做透明方式,就是说Componet中声明所以用来管理子对象的方法,包括Add和Remove,实现Componet的所有子类都具备了Add和Remove。这样做的 好处就是叶节点和枝结点对于外界没有区别,具备完全一致的行为方法。但是问题也很明显,Leaf内的Add和Remove方法是没意义的

如果不希望Leaf内有无用的方法,可以采用安全方式,也就是在Componet中不声明Add和Remove方法,子类Leaf就不需要实现它,而是在Composite声明管理子类对象的方法,这样就不会出现刚刚出现的问题,但是由于不够透明,叶节点和枝结点将不具有相同的接口,客户端的调用需要做相应的判断,带来了不便

何时使用组合模式:需求中体现部分和整体层次的结构时,以及希望用户可以忽略组合对象和单个对象的不同,统一地使用组合结构中的所以对象时

组合模式的好处:定义的基本对象可以被组合成更复杂的组合对象,而组合对象又可以被组合,如此递归下去,客户端中,任何用到基本对象的地方都可以使用组合对象。用户不用去关系处理的是叶节点还是组合组件。

组合模式可以让客户一致地使用组合结构和单个对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值