23个java设计模式(十五)-- 组合模式

2016年03月23日 原创
关键词: java 设计模式
摘要 组合模式将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使用户对单个对象和组合对象的使用具有一致性。

一、概述。

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

如果一个对象包含另一个对象的引用,称这样的对象为组合对象。如果将当前组合对象作为一个整体的话,那么它所包含的对象就是该整体的一部分。如果一个对象不含有其他对象的引用,称这样的对象为个体对象。在编写程序时,我们希望将许多个体对象和组合对象组成树形结构,以此表示“部分-整体”的层次结构,并借助该层次结构使得用户能用一致的方式处理个体对象和组合对象。在组成的树形结构中,个体对象和组合对象都是树中的节点,但是,组合对象是具有其他子节点的节点,个体对象是不具有其他子节点的叶节点。

组合模式使关于怎样将对象形成树形结构来表现整体和部分的层次结构的成熟模式。使用组合模式,可以让用户以一致的方式处理个体对象和组合对象,组合模式的关键在于无论是个体对象还是组合对象都实现了相同的结构或都是同一个抽象类的子类。

二、组合模式的结构。

组合模式包括三种角色:

  • 抽象组件(Component):是一个接口(抽象类),该接口(抽象类)定义了个体对象和组合对象需要实现的操作。
  • 组合节点(Composite Node):实现Component接口的实例,含有其他组合节点或者叶子节点的引用。
  • 叶子节点(Leaf Node):实现Component接口的实例,没有其他节点的引用。

三、示例程序。

抽象组件(Component)

MilitaryPerson.java

public interface MilitaryPerson {
	public void add(MilitaryPerson person);
	public void remove(MilitaryPerson person);
	public MilitaryPerson getChild(int index);
	public Iterator<MilitaryPerson> getAllChildren();
	public boolean isSoldier();
	public double getSalary();
	public void setSalary(double salary);
	
}

组合节点(Composite Node)

MilitaryOfficer.java

public class MilitaryOfficer implements MilitaryPerson{
	private LinkedList<MilitaryPerson> list;
	private String name;
	private double salary;
	public MilitaryOfficer(String name, double salary) {
		this.name = name;
		this.salary = salary;
		this.list = new LinkedList<>();
	}
	@Override
	public void add(MilitaryPerson person) {
		list.add(person);
	}
	@Override
	public void remove(MilitaryPerson person) {
		list.remove(person);
	}
	@Override
	public MilitaryPerson getChild(int index) {
		return list.get(index);
	}
	@Override
	public Iterator<MilitaryPerson> getAllChildren() {
		return list.iterator();
	}
	@Override
	public boolean isSoldier() {
		return false;
	}
	@Override
	public double getSalary() {
		return salary;
	}
	@Override
	public void setSalary(double salary) {
		this.salary = salary;
	}
	
}

叶子节点(Leaf Node)

MilitarySoldier.java

public class MilitarySoldier implements MilitaryPerson{
	private double salary;
	private String name;
	
	public MilitarySoldier(double salary, String name) {
		this.salary = salary;
		this.name = name;
	}

	@Override
	public void add(MilitaryPerson person) {
		
	}

	@Override
	public void remove(MilitaryPerson person) {
		
	}

	@Override
	public MilitaryPerson getChild(int index) {
		return null;
	}

	@Override
	public Iterator<MilitaryPerson> getAllChildren() {
		return null;
	}

	@Override
	public boolean isSoldier() {
		return true;
	}

	@Override
	public double getSalary() {
		return salary;
	}

	@Override
	public void setSalary(double salary) {
		this.salary =  salary;
		
	}

}

测试程序

ComputeSalary.java

public class ComputeSalary {
	public static double computeSalary(MilitaryPerson person) {
		double sum = 0;
		if(person.isSoldier())
			sum+=person.getSalary();
		else {
			sum+=person.getSalary();
			Iterator<MilitaryPerson> iter = person.getAllChildren();
			while(iter.hasNext()) sum += computeSalary(iter.next());
		}
		return sum;
	}
}

Example1Test.java

public class Example1Test {
	@Test
	public void testMain() {
		MilitaryPerson companyCommander = new MilitaryOfficer("连长", 5000);
		MilitaryPerson platoonLeader1 = new MilitaryOfficer("一排长", 4000);
		MilitaryPerson platoonLeader2 = new MilitaryOfficer("二排长", 4000);
		MilitaryPerson monitor11 = new MilitaryOfficer("一班长", 2000);
		MilitaryPerson monitor12 = new MilitaryOfficer("二班长", 2000);
		MilitaryPerson monitor13 = new MilitaryOfficer("三班长", 2000);
		MilitaryPerson monitor21 = new MilitaryOfficer("一班长", 2000);
		MilitaryPerson monitor22 = new MilitaryOfficer("二班长", 2000);
		MilitaryPerson monitor23 = new MilitaryOfficer("三班长", 2000);
		MilitaryPerson soldiers[] = new MilitaryPerson[60];
		for(int i = 0; i < soldiers.length; i++) {
			soldiers[i] = new MilitarySoldier(1000, "小兵");
		}
		companyCommander.add(platoonLeader1);
		companyCommander.add(platoonLeader2);
		platoonLeader1.add(monitor11);
		platoonLeader1.add(monitor12);
		platoonLeader1.add(monitor13);
		platoonLeader2.add(monitor21);
		platoonLeader2.add(monitor22);
		platoonLeader2.add(monitor23);
		for(int i = 0; i <= 9; i++) {
			monitor11.add(soldiers[i]);
			monitor12.add(soldiers[i+10]);
			monitor13.add(soldiers[i+20]);
			monitor21.add(soldiers[i+30]);
			monitor22.add(soldiers[i+40]);
			monitor23.add(soldiers[i+50]);
		}
		System.out.println("一排的军饷:"+ComputeSalary.computeSalary(platoonLeader1));
		System.out.println("二排一班的军饷:"+ComputeSalary.computeSalary(monitor21));
		System.out.println("全连的军饷:"+ComputeSalary.computeSalary(companyCommander));
	}
}

四、组合模式的优点。

  1. 组合模式中包含个体对象和组合对象,并形成树形结构,使用户可以方便地处理个体对象和组合对象。
  2. 组合对象和个体对象实现了相同的接口,用户一般无须区分个体对象和组合对象。
  3. 当增加新的组合节点和叶子节点时,用户的重要代码不需要作出修改。

五、适合组合模式的场景。

  1. 当想表示对象的“部分-整体”层次结构。
  2. 希望用户用一致的方法处理个体对象和组合对象。