* 24种设计模式——组合模式

将对象组合成树形结构,以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

一、公司组织架构1(接口篇)


1. 公司人员接口

public interface ICorp {
	//获取自己的信息(每个员工都有信息,你想隐藏,门儿都没有)
	public String getInfo();
}
2. 树叶接口

public interface ILeaf extends ICorp{
	
}
3. 树枝接口(包括大老板节点 和 经理节点 )

public interface IBranch extends ICorp{
	//能够增加小兵(树叶节点)或者是经理(树枝节点)—— 不管传什么都是向上造型
	public void addSubordinate(ICorp corp);
	//我还要能够获得下属的信息
	public ArrayList<ICorp> getSubordinate();
}
4. 树叶实现类

public class Leaf implements ILeaf{
	//叶子叫什么名字
	private String name = "";
	//叶子的职位
	private String position = "";
	//叶子的薪水
	private int salary = 0;
	//通过构造函数传递信息
	public Leaf(String name, String position, int salary) {
		this.name = name;
		this.position = position;
		this.salary = salary;
	}
	//最小的小兵只能获得自己的信息了
	public String getInfo() {
		String info = "";
		info = "名称:"+this.name;
		info = info + "\t职位:"+this.position;
		info = info + "\t薪水:"+this.salary;
		return info;
	}
}
5. 树枝实现类

public class Branch implements IBranch{
	//存储子节点的信息
	private ArrayList subordinateList = new ArrayList();
	//树枝节点的名称
	private String name = "";
	//树枝节点的职位
	private String position = "";
	//树枝节点的薪水
	private int salary = 0;
	//通过构造函数传递树枝节点的参数
	public Branch(String name, String position,int salary) {
		this.name = name;
		this.position = position;
		this.salary = salary;
	}
	//增加一个下属,可能 是小头目,也可能是个小兵
	public void addSubordinate(ICorp corp) {
		this.subordinateList.add(corp);
	}
	//我有哪些下属
	public ArrayList<ICorp> getSubordinate() {
		return this.subordinateList;
	}
	//得到自己的信息
	public String getInfo() {
		String info = "";
		info = "名称:"+this.name;
		info = info + "\t职位:"+this.position;
		info = info + "\t薪水:"+this.salary;
		return info;
	}
}
6. 场景类

public class Client {
	public static void main(String[] args) {
		//首先是组装一个组织结构出来 
		Branch ceo = compositeCorpTree();
		//首先把ceo的信息打印出来
		System.out.println(ceo.getInfo());
		//然后是所有员工信息
		System.out.println(getTreeInfo(ceo));
	}
	
	public static Branch compositeCorpTree(){
		//首先产生总经理CEO
		Branch root = new Branch("王大麻子", "总经理", 100000);
		//把三个部门经理产生出来 
		Branch developDep = new Branch("刘大瘸子", "研发部门经理", 10000);
		Branch salesDep = new Branch("马二拐子", "销售部门经理", 20000);
		Branch financeDep = new Branch("赵三驼子", "财务部门经理", 30000);
		//再把三个小组长产生出来 
		Branch firstDevGroup = new Branch("杨三也斜","开发一组组长",5000);
		Branch secondDevGroup = new Branch("吴大植株","开发二组组长",6000);
		//把所有的小兵都产生出来 
		Leaf a = new Leaf("a","开发人员",2000);
		Leaf b = new Leaf("b","开发人员",2000);
		Leaf c = new Leaf("c","开发人员",2000);
		Leaf d = new Leaf("d","开发人员",2000);
		Leaf e = new Leaf("e","开发人员",2000);
		Leaf f = new Leaf("f","开发人员",2000);
		Leaf g = new Leaf("g","开发人员",2000);
		Leaf h = new Leaf("h", "销售人员", 5000);
		Leaf i = new Leaf("i", "销售人员", 4000);
		Leaf j = new Leaf("j", "财务人员", 5000);
		Leaf k = new Leaf("k", "CEO秘书", 8000);
		Leaf zhengLaoLiu = new Leaf("郑老六", "研发部副经理", 20000);
		//开始组装
		//CEO下有三个部门经理和一个秘书
		root.addSubordinate(developDep);
		root.addSubordinate(salesDep);
		root.addSubordinate(financeDep);
		root.addSubordinate(k);
		//研发部经理
		developDep.addSubordinate(firstDevGroup);
		developDep.addSubordinate(secondDevGroup);
		developDep.addSubordinate(zhengLaoLiu);
		//看看两个开发小组下有什么
		firstDevGroup.addSubordinate(a);
		firstDevGroup.addSubordinate(b);
		firstDevGroup.addSubordinate(c);
		secondDevGroup.addSubordinate(d);
		secondDevGroup.addSubordinate(e);
		secondDevGroup.addSubordinate(f);
		//再看销售部下的人员情况
		salesDep.addSubordinate(h);
		salesDep.addSubordinate(i);
		//最后一个财务
		financeDep.addSubordinate(j);
		return root;
	}
	//遍历整棵树,只要给我根节点,我就能遍历出所有的节点
	public static String getTreeInfo(Branch root){
		List<ICorp> subordinateList = root.getSubordinate();
		String info = "";
		for(ICorp s : subordinateList){
			if(s instanceof Leaf){
				info = info + s.getInfo() + "\n";
			}else{	//是个小头目
				info = info + s.getInfo() + "\n" + getTreeInfo((Branch)s);
			}
		}
		return info;
	}
}
二、公司组织架构(抽象类篇)


主要是把ICorp接口修改为Corp抽象类,抽象出来很多公共地方,方便很多。

1. 抽象公司职员类

public abstract class Corp {
	//公司每个人都有名称
	private String name = "";
	//公司每个人都有职位
	private String position = "";
	//公司每个人都有薪水
	private int salary = 0;
	public Corp(String name, String position, int salary) {
		this.name = name;
		this.position = position;
		this.salary = salary;
	}
	//获取员工信息
	public String getInfo(){
		String info = "";
		info = "名称:"+this.name;
		info = info + "\t职位:"+this.position;
		info = info + "\t薪水:"+this.salary;
		return info;
	}
}
2. 树叶节点

public class Leaf extends Corp{
	//就写一个构造函数,这个是必须 的
	public Leaf(String name, String position, int salary) {
		super(name, position, salary);
	}
}
3. 树枝节点 

public class Branch extends Corp{
	//存储子节点的信息
	private ArrayList subordinateList = new ArrayList();
	//构造函数是必须 的
	public Branch(String name, String position, int salary) {
		super(name, position, salary);
	}
	//增加一个下属,可能 是小头目,也可能是个小兵
	public void addSubordinate(Corp corp) {
		this.subordinateList.add(corp);
	}
	//我有哪些下属
	public ArrayList<Corp> getSubordinate() {
		return this.subordinateList;
	}
}
4. 稍稍修改场景类

代码太长,同上例,修改其中部分方法

//遍历整棵树,只要给我根节点,我就能遍历出所有的节点
public static String getTreeInfo(Branch root){
	List<Corp> subordinateList = root.getSubordinate();
	String info = "";
	for(Corp s : subordinateList){
		if(s instanceof Leaf){
			info = info + s.getInfo() + "\n";
		}else{	//是个小头目
			info = info + s.getInfo() + "\n" + getTreeInfo((Branch)s);
		}
	}
	return info;
}
三、组合模式定义


Component抽象构件角色:定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性,比如我们例子中的getInfo就封装到了抽象类中

Leaf叶子构件:叶子对象,其下再也没有其它分支,也就是遍历的最小单位。

Composite树枝构件:树枝对象,作用是组合树枝节点和叶子节点形成一个树形结构。

1. 抽象构件

public abstract class Component {
	//个体和整体都具有的共享
	public void doSomething(){
		//编写业务逻辑
	}
}
2. 树枝构件

public class Composite extends Component{
	//构件容器
	private List<Component> componentArrayList = new ArrayList<Component>();
	//增加一个叶子构件或树枝构件
	public void add(Component component){
		this.componentArrayList.add(component);
	}
	//删除一个叶子构件或树枝构件
	public void remove(Component component){
		this.componentArrayList.remove(component);
	}
	//获得分支下的所有叶子构件和树枝构件
	public List<Component> getChildren(){
		return this.componentArrayList;
	}
}
3. 树叶构件

public class Leaf extends Component{
	/*
	 * 可以覆写父类方法
	 * public void doSomething(){
	 * 
	 * }
	 */
}
4. 场景类

public class Client {
	public static void main(String[] args) {
		//创建一个根节点
		Composite root = new Composite();
		root.doSomething();
		//创建一个树枝构件
		Composite branch = new Composite();
		//创建一个叶子节点 
		Leaf leaf = new Leaf();
		//建立整体
		root.add(branch);
		branch.add(leaf);
	}
	//通过递归遍历树
	public static void display(Composite root){
		for(Component c:root.getChildren()){	//叶子节点
			if(c instanceof Leaf){
				c.doSomething();
			}else{	//树枝节点 
				display((Composite)c);
			}
		}
	}
}
四、组合模式的应用

1.优点:

高层模块调用简单:一棵树形机构中的所有节点都是Component,局部和整体对调用者来说没有任何区别,也就是说,高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。

节点自由增加:使用组合模式后,如果想增加一个树枝节点、树叶节点都很容易,只要找到它的父节点就成,符合开闭原则。

2. 缺点

看到在我们的场景类中定义,提到树叶和树枝使用时的定义了吗?直接使用了实现类!这在面向接口编程上是很不恰当的,与依赖倒置原则冲突,读者在使用时要考虑清楚,它限制了你接口的影响范围

3. 使用用场景

1)维护和展示部分-整体关系的场景,如树形菜单、文件和文件夹管理。

2)从一个整体中能够独立出部分模块或功能的场景。

4. 组合模式的注意事项

只要是树形结构,就要考虑使用组合模式,这个一定要记住,只要是要体现局部和整体的关系的时候,而且这种关系还可能比较深,考虑一下组合模式吧
五、组合模式的扩展
1. 真实的组合模式

上述Client程序没没有改变多少,树的组装是跑不了的,但树的组装并不是像例子中的new,而是一般先有一张数据库的表,这张数据表定义了一个树形结构,我们把它读取出来,然后展现到前台上,用for循环加上递归就可以完成这个读取,


2. 透明的组合模式(一般用安全模式就好)

我们上面的例子是安全模式,下面将下透明模式,透明模式是把用来组合使用的方法放到抽象中,比如add()、remove()以及getChildren等方法(),不管叶子对象不是树枝对象都有相同的结构,通过判断是getChildren的返回值确认是叶子节点 不是树枝节点,如果处理不当会在运行期出现错误,所以建议用上述例子中的安全模式。

1) 抽象构件

public abstract class Component {
	//个体和整体都具有的共享
	public void doSomething(){
		//编写业务逻辑
	}
	//增加一个叶子构件或树枝构件
	public abstract void add(Component component);
	//删除一个叶子构件或树枝构件
	public abstract void remove(Component component);
	//获得分支下的所有叶子构件和树枝构件
	public abstract ArrayList<Component> getChildren();
}
2) 树叶节点 

public class Leaf extends Component{
	public void add(Component component) {
		//空实现,直接抛一个“不支持请求”异常
		throw new UnsupportedOperationException();
	}
	public void remove(Component component) {
		//空实现,直接抛一个“不支持请求”异常
		throw new UnsupportedOperationException();
	}
	public ArrayList<Component> getChildren() {
		//空实现,直接抛一个“不支持请求”异常
		throw new UnsupportedOperationException();
	}
}
3) 树结构遍历

public class Client {
	public static void main(String[] args) {
		
	}
	//通过递归遍历树
	public static void display(Component root){
		for(Component c:root.getChildren()){
			if(c instanceof Leaf){
				c.doSomething();
			}else{	//树枝节点
				display(c);
			}
		}
	}
}
3. 组合模式的遍历(获取父节点)

上面例子是从上向下获取子节点,如果我想获取父节点,可以这样做

1)抽象构件

public abstract class Corp {
	//公司每个人都有名称
	private String name = "";
	//公司每个人都有职位
	private String position = "";
	//公司每个人都有薪水
	private int salary = 0;
	//父节点是谁
	private Corp parent = null;
	public Corp(String name, String position, int salary) {
		this.name = name;
		this.position = position;
		this.salary = salary;
	}
	//获取员工信息
	public String getInfo(){
		String info = "";
		info = "名称:"+this.name;
		info = info + "\t职位:"+this.position;
		info = info + "\t薪水:"+this.salary;
		return info;
	}
	//设置父节点
	protected void setParent(Corp _parent){
		this.parent = _parent;
	}
	//得到父节点
	public Corp getParent(){
		return this.parent;
	}
}
2)树枝构件

public class Branch extends Corp{
	//存储子节点的信息
	private ArrayList subordinateList = new ArrayList();
	//构造函数是必须 的
	public Branch(String name, String position, int salary) {
		super(name, position, salary);
	}
	//增加一个下属,可能 是小头目,也可能是个小兵
	public void addSubordinate(Corp corp) {
		corp.setParent(this);	//设置父节点 
		this.subordinateList.add(corp);
	}
	//我有哪些下属
	public ArrayList<Corp> getSubordinate() {
		return this.subordinateList;
	}
}
六、最佳实践

一般主页左边的导航菜单或者有树形结构的模块都可以考虑。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值