结构型模式-组合模式(树形结构的处理)

[Toc]java

树形结构在软件中随处可见,例如操做系统中的目录结构、应用软件中的菜单、办公系统中的公司组织结构等。git

组合模式经过一种巧妙的设计方案使得用户能够一致性地处理整个树形结构或者树形结构的一部分,也能够一致性地处理树形结构中的叶子节点(不包含子节点的节点)和容器节点(包含子节点的节点)。编程

1. 定义

组合模式(Composite Pattern):组合多个对象造成树形结构以表示具备“总体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具备一致性,组合模式又能够称为“总体—部分”(Part-Whole)模式,它是一种对象结构型模式。设计模式

2. 结构

在组合模式中引入了抽象构件类Component,它是全部容器类和叶子类的公共父类,客户端针对Component进行编程。组合模式结构如图所示:安全

组合模式

  • Component(抽象构件):它能够是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中能够包含全部子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增长子构件、删除子构件、获取子构件等。
  • Leaf(叶子构件):它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,能够经过异常等方式进行处理。
  • Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点能够是叶子节点,也能够是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中能够递归调用其子节点的业务方法。

3. 代码实现

代码实现了一个公司的组织架构,包括各级公司,各级公司包括各部门,AbstractOrganization充当抽象构建类,Company充当容器构建类(能够定义其余容器构建类),Department充当叶子构建类(能够定义其余叶子构建类)。架构

AbstractOrganizationide

public abstract class AbstractOrganization {

	public abstract void add(AbstractOrganization organization);

	public abstract void remove(AbstractOrganization organization);

	public abstract  AbstractOrganization getChild(int i);

	public abstract void notifyMessage();

}

Companythis

public class Company extends AbstractOrganization {

	private List<AbstractOrganization> organizationList=new ArrayList<>();
	private String name;

	public Company(String name) {
		this.name = name;
	}

	@Override
	public void add(AbstractOrganization organization) {
		organizationList.add(organization);
	}

	@Override
	public void remove(AbstractOrganization organization) {
		organization.remove(organization);
	}

	@Override
	public AbstractOrganization getChild(int i) {
		return organizationList.get(i);
	}

	@Override
	public void notifyMessage() {
		System.out.println("对公司:"+name+" 进行通知");
		for (AbstractOrganization organization:organizationList){
			organization.notifyMessage();
		}
	}
}

Department操作系统

public class Department extends AbstractOrganization {

	private String name;

	public Department(String name) {
		this.name = name;
	}

	@Override
	public void add(AbstractOrganization organization) {
		System.out.println("对不起,不支持该方法!");
	}

	@Override
	public void remove(AbstractOrganization organization) {
		System.out.println("对不起,不支持该方法!");
	}

	@Override
	public AbstractOrganization getChild(int i) {
		System.out.println("对不起,不支持该方法!");
		return null;
	}

	@Override
	public void notifyMessage() {
		System.out.println("对"+name+" 进行通知");
	}
}

Client设计

public class Client {

	public static void main(String[] args) {
		AbstractOrganization c1,c2,d1,d2,d3;
		c1=new Company("总公司");
		c2=new Company("分公司1");
		d1=new Department("总公司部门1");
		d2=new Department("分公司部门1");
		d3=new Department("分公司部门2");
		c1.add(c2);
		c1.add(d1);
		c2.add(d2);
		c2.add(d3);
		//客户端无序关心节点的层次结构,对节点能够进行统一处理
		c1.notifyMessage();
		System.out.println("-------------");
		c2.notifyMessage();
	}
}

//对公司:总公司 进行通知
//对公司:分公司1 进行通知
//对分公司部门1 进行通知
//对分公司部门2 进行通知
//对总公司部门1 进行通知
//-------------
//对公司:分公司1 进行通知
//对分公司部门1 进行通知
//对分公司部门2 进行通知

4. 透明组合模式与安全组合模式

4.1 透明组合模式

透明组合模式中,抽象构件Component中声明了全部用于管理成员对象的方法,包括add()、remove()以及getChild()等方法,这样作的好处是确保全部的构件类都有相同的接口。在客户端看来,叶子对象与容器对象所提供的方法是一致的,客户端能够相同地对待全部的对象。

透明组合模式的缺点是不够安全,由于叶子对象和容器对象在本质上是有区别的。叶子对象不可能有下一个层次的对象,即不可能包含成员对象,所以为其提供add()、remove()以及getChild()等方法是没有意义的,这在编译阶段不会出错,但在运行阶段若是调用这些方法可能会出错(若是没有提供相应的错误处理代码)。

4.1 安全组合模式

Java AWT中使用的组合模式就是安全组合模式。

安全组合模式中,在抽象构件Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法。这种作法是安全的,由于根本不向叶子对象提供这些管理成员对象的方法,对于叶子对象,客户端不可能调用到这些方法。

安全组合模式的缺点是不够透明,由于叶子构件和容器构件具备不一样的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,所以客户端不能彻底针对抽象编程,必须有区别地对待叶子构件和容器构件。

客户端须要指定具体的容器类型,才能调用管理成员对象的方法。

Comapany c1,c2;
AbstractOrganization d1,d2,d3;
...
c1.notifyMessage();

5. 优缺点

  • 优势
  1. 组合模式能够清楚地定义分层次的复杂对象,表示对象的所有或部分层次,它让客户端忽略了层次的差别,方便对整个层次结构进行控制。
  2. 客户端能够一致地使用一个组合结构或其中单个对象,简化客户端代码。
  3. 在组合模式中增长新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合“开闭原则”。
  4. 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,经过叶子对象和容器对象的递归组合,能够造成复杂的树形结构,但对树形结构的控制却很是简单。
  • 缺点
  1. 在增长新构件时很难对容器中的构件类型进行限制。由于它们都来自于相同的抽象层,在这种状况下,必须经过在运行时进行类型检查来实现,这个实现过程较为复杂。

6. 适用场景

  1. 在具备总体和部分的层次结构中,但愿经过一种方式忽略总体与部分的差别,客户端能够一致地对待它们。
  2. 在一个使用面向对象语言开发的系统中须要处理一个树形结构
  3. 在一个系统中可以分离出叶子对象和容器对象,并且它们的类型不固定,须要增长一些新的类型。

7. 我的理解

组合模式用户处理相似树形结构的包含容器对象和叶子对象的层次结构,经过该模式可忽略总体与部分的差别,让客户端统一对待它们,同时符合“开闭原则”利于扩展。

参考

  1. Java设计模式-刘伟
相关文章
相关标签/搜索