将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。
Component(抽象构件):为叶子构件和组合构件声明统一的接口,它可以是抽象类也可以是接口。
Leaf(叶子构件):它在组合结构中表示叶子节点对象,它没有子节点,所以对于操作子节点的接口方法通过抛出异常来说明。
Composite(容器构件):它是组合结构中的容器节点对象,它的子节点可以使叶子节点对象,也可以是容器节点对象,它提供了一个list集合用于存放子节点。
Component:
abstract class Component {
protected String name;
public abstract void add(Component c);
public abstract void remove(Component c);
public abstract Component getChild(int i);
public abstract void display();
}
Leaf:
public class Leaf extends Component{
public Leaf(String name){
this.name = name;
}
@Override
public void add(Component c) {
System.err.println("can not add");
}
@Override
public void remove(Component c) {
System.err.println("can not remove");
}
@Override
public Component getChild(int i) {
System.err.println("can not getChild");
return null;
}
@Override
public void display() {
System.out.println(name);
}
}
Composite:
public class Composite extends Component{
ArrayList children = new ArrayList();
public Composite(String name){
this.name = name;
}
@Override
public void add(Component c) {
children.add(c);
}
@Override
public void remove(Component c) {
children.remove(c);
}
@Override
public Component getChild(int i) {
return children.get(i);
}
@Override
public void display() {
for (Component c : children) {
System.out.println(c.name);
}
}
}
测试类:
public static void main(String[] args) {
Component composite = new Composite("容器节点A");
composite.add(new Composite("容器节点AX"));
composite.add(new Composite("容器节点AY"));
composite.display();
Leaf leaf = new Leaf("叶子节点B");
leaf.display();
}
测试结果:
我将以公司管理系统作为案例,我们都知道一个公司做大做强后,必然需要在各个城市建立分公司来开拓市场,那么总公司的办公管理系统需要能复用到分公司,也就是说总公司调用管理功能的方法和分公司调用管理功能的方法最好是一致的。
Company:
public abstract class Company {
protected String name;
public abstract void add(Company c);
public abstract void remove(Company c);
public abstract void display(int length);
public abstract void operate();
}
具体分公司(ConcreteCompany):
public class ConcreteCompany extends Company{
ArrayList list = new ArrayList();
public ConcreteCompany(String name){
this.name = name;
}
@Override
public void add(Company c) {
list.add(c);
}
@Override
public void remove(Company c) {
list.remove(c);
}
@Override
public void display(int length) {
for (int i = 0; i < length; i++) {
System.out.print("-");
}
System.out.println(this.name);
for (Company c : list) {
c.display(length+2);
}
}
@Override
public void operate() {
for (Company c : list) {
c.operate();
}
}
}
人力资源管理部门:
public class HumanResource extends Company{
public HumanResource(String name){
this.name = name;
}
@Override
public void add(Company c) {
System.err.println("can not add");
}
@Override
public void remove(Company c) {
System.err.println("can not remove");
}
@Override
public void display(int length) {
for (int i = 0; i < length; i++) {
System.out.print("-");
}
System.out.println(this.name);
}
@Override
public void operate() {
System.out.println(this.name+":人力资源管理");
}
}
财务部门:
public class FinancialManagement extends Company{
public FinancialManagement(String name){
this.name = name;
}
@Override
public void add(Company c) {
System.err.println("can not add");
}
@Override
public void remove(Company c) {
System.err.println("can not remove");
}
@Override
public void display(int length) {
for (int i = 0; i < length; i++) {
System.out.print("-");
}
System.out.println(this.name);
}
@Override
public void operate() {
System.out.println(this.name+":财务管理");
}
}
测试类:
public static void main(String[] args) {
ConcreteCompany company = new ConcreteCompany("北京总公司");
ConcreteCompany company1 = new ConcreteCompany("上海华东分公司");
HumanResource humanResource = new HumanResource("总公司人力资源部");
FinancialManagement humanResource1 = new FinancialManagement("总公司财务部");
company.add(humanResource);
company.add(humanResource1);
company.add(company1);
HumanResource humanResource2 = new HumanResource("华东分公司人力资源部");
FinancialManagement humanResource3 = new FinancialManagement("华东分公司财务部");
ConcreteCompany company2 = new ConcreteCompany("南京办事处");
company1.add(humanResource2);
company1.add(humanResource3);
company1.add(company2);
HumanResource humanResource4 = new HumanResource("南京办事处人力资源部");
FinancialManagement humanResource5 = new FinancialManagement("南京办事处财务部");
company2.add(humanResource4);
company2.add(humanResource5);
System.out.println("公司组织架构:");
company.display(2);
System.out.println("部门职责:");
company.operate();
}
测试结果:
客户端可以一致的使用组合节点对象和单个节点对象,无需写判断代码,简化代码。
在增加新构件时很难对容器中的构件类型进行限制。有时候我们希望一个容器中只能有某些特定类型的对象,例如在某个文件夹中只能包含文本文件,使用组合模式时,不能依赖类型系统来施加这些约束,因为它们都来自于相同的抽象层,在这种情况下,必须通过在运行时进行类型检查来实现,这个实现过程较为复杂
List、Map、Set中addAll方法的参数是它本身的一个集合形式,这体现了整体和部分都适用于同一个接口。