组合模式
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使用户对单个对象和组合对象的使用具有一致性。
Composite Pattern
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
类图
模式的结构与使用
组合方法模式的结构中包括三种角色。
+ 抽象组件(Abstract Component):是一个接口(抽象类),该接口(抽象类)定义了个体对象和组合对象需要实现的关于操作其子节点的方法,比如add()、remove()以及getChild()等方法。抽象组件也可以定义个体对象和组合对象用于操作其自身的方法,比如isLeaf()方法等。
+ Composite(Composite Node):实现Component接口类的实例,Composite节点不仅实现Component接口,而且可以含有其他Composite节点或Leaf节点的引用。
+ Leaf节点(Leaf Node):实现Component接口类的实例,Leaf节点实现Composite接口,不可以含有其他Composite节点或Leaf节点的引用,因此,叶节点在实现Component接口有关操作子节点的方法时,比如add()、remove()和getChild()方法,可让方法抛出一个异常,也可以实现为空操作。
简单的例子
Component的接口类MilitaryPerson.java
package Component;
import java.util.Iterator;
public interface MilitaryPerson {
public void add(MilitaryPerson person);
public void remove(MilitaryPerson person);
public MilitaryPerson getChild(int index);
public Iterator<MilitaryPerson> getAllChildren();
public boolean isLeaf();
public double getSalary();
public void setSalary(double salary);
}
Composite的实现类MilitaryOfficer.java
package Component;
import java.util.Iterator;
import java.util.LinkedList;
public class MilitaryOfficer implements MilitaryPerson {
LinkedList<MilitaryPerson> list;
String name;
double salary;
public MilitaryOfficer(String name, double salary) {
this.name = name;
this.salary = salary;
list = new LinkedList<MilitaryPerson>();
}
@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 isLeaf() {
return false;
}
@Override
public double getSalary() {
return salary;
}
@Override
public void setSalary(double salary) {
this.salary = salary;
}
}
Leaf的实现类MilitarySoldier.java
package Component;
import java.util.Iterator;
public class MilitarySoldier implements MilitaryPerson {
double salary;
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 isLeaf() {
return true;
}
@Override
public double getSalary() {
return salary;
}
@Override
public void setSalary(double salary) {
this.salary = salary;
}
}
计算工资的工具类ComputerSalary.java
package Component;
import java.util.Iterator;
public class ComputerSalary {
public static double computerSalary(MilitaryPerson person) {
double sum = 0;
if (person.isLeaf() == true) {
sum = sum + person.getSalary();
}
if (person.isLeaf() == false) {
sum = sum + person.getSalary();
Iterator<MilitaryPerson> iterator = person.getAllChildren();
while (iterator.hasNext()) {
MilitaryPerson p = iterator.next();
sum = sum + computerSalary(p);
}
}
return sum;
}
}
测试类Application.java
package Component;
public class Application {
public static void main(String[] args) {
MilitaryPerson 连长 = new MilitaryOfficer("连长", 5000);
MilitaryPerson 排长1 = new MilitaryOfficer("一排长", 4000);
MilitaryPerson 排长2 = new MilitaryOfficer("二排长", 4000);
MilitaryPerson 排长3 = new MilitaryOfficer("三排长", 4000);
MilitaryPerson 班长11 = new MilitaryOfficer("一排长", 2000);
MilitaryPerson 班长12 = new MilitaryOfficer("二排长", 2000);
MilitaryPerson 班长13 = new MilitaryOfficer("三排长", 2000);
MilitaryPerson 班长21 = new MilitaryOfficer("一排长", 2000);
MilitaryPerson 班长22 = new MilitaryOfficer("二排长", 2000);
MilitaryPerson 班长23 = new MilitaryOfficer("三排长", 2000);
MilitaryPerson 班长31 = new MilitaryOfficer("一排长", 2000);
MilitaryPerson 班长32 = new MilitaryOfficer("二排长", 2000);
MilitaryPerson 班长33 = new MilitaryOfficer("三排长", 2000);
MilitaryPerson[] 士兵 = new MilitarySoldier[90];
for (int i = 0; i < 士兵.length; i++) {
士兵[i] = new MilitarySoldier(1000, "小兵");
}
连长.add(排长1);
连长.add(排长2);
排长1.add(班长11);
排长1.add(班长12);
排长1.add(班长13);
排长2.add(班长21);
排长2.add(班长22);
排长2.add(班长23);
排长3.add(班长31);
排长3.add(班长32);
排长3.add(班长33);
for (int i = 0; i <= 9; i++) {
班长11.add(士兵[i]);
班长12.add(士兵[i + 10]);
班长13.add(士兵[i + 20]);
班长21.add(士兵[i + 30]);
班长22.add(士兵[i + 40]);
班长23.add(士兵[i + 50]);
班长31.add(士兵[i + 60]);
班长32.add(士兵[i + 70]);
班长33.add(士兵[i + 80]);
}
System.out.println("一排的军饷:" + ComputerSalary.computerSalary(排长1));
System.out.println("一班的军饷:" + ComputerSalary.computerSalary(班长11));
System.out.println("全连的军饷:" + ComputerSalary.computerSalary(连长));
}
}
执行效果图
组合模式的优点
- 组合模式中包含个体对象和组合对象,并形成树形结构,使用户可以方便地处理个体对象和组合对象。
- 组合对象和个体对象实现了相同的接口,用户一般无须区分个体对象和组合对象。
- 当增加新的Composite节点和Leaf节点时,用户的重要代码不需要作出修改,例如,如果增加一个创建企业领导和一般职员的Composite节点和Leaf节点,那么ComputerSalary并不需要修改,就可以计算一个部门的薪水总和。
适用组合模式的情景
- 当想表示对象的部分-整体层次结构。
- 希望用户用一致的方式处理个体对象和组合对象。