//调用所有子节点的操作

    for (Component component : components) {

         component.operation();

    }

}

@Override

public void add(Component c) {

    components.add(c);

}

@Override

public void remove(Component c) {

    components.remove(c);

}

@Override

public Component getChild(int i) {

    return components.get(i);

}

@Override

public List<Component> getChildren() {

    return components;

}

}


public class Leaf extends Component {

    public Leaf(String name) {

        super(name);

    }

    @Override

    public void operation() {

        System.out.println("叶节点"+name+"的操作");

    }

}

public class Client {

public static void main(String[] args) {

    //创建根节点对象

    Component component = new Composite("component");

    //创建两个组合节点对象

    Component composite1 = new Composite("composite1");

    Component composite2 = new Composite("composite2");

    //将两个组合节点对象添加到根节点

    component.add(composite1);

    component.add(composite2);

    //给第一个组合节点对象添加两个叶子节点

    Component leaf1 = new Leaf("leaf1");

    Component leaf2 = new Leaf("leaf2");

    composite1.add(leaf1);

    composite1.add(leaf2);

    //给第二个组合节点对象添加一个叶子节点和一个组合节点

    Component leaf3 = new Leaf("leaf3");

    Component composite3 = new Composite("composite3");

    composite2.add(leaf3);

    composite2.add(composite3);

    //给第二个组合节点下面的组合节点添加两个叶子节点

    Component leaf4 = new Leaf("leaf4");

    Component leaf5 = new Leaf("leaf5");

    composite3.add(leaf4);

    composite3.add(leaf5);

    //执行所有节点的操作

    component.operation();

}

}


输出结果:  

![这里写图片描述](https://img-blog.csdn.net/20180524015313319?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2x5YWJjMTIzNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)  

 上述代码中,在组合节点对象Composite的operation()方法中除了执行自身的操作外,还调用了子节点的operation()方法,这样使得客户端可以透明的遍历所有的节点对象的操作,而不用关心操作的是叶子节点还是组合节点,将它们一视同仁。这看上去有点像二叉树的遍历,不过这里并不是二叉树,每个组合节点可以有若干个子节点,而这些子节点,如果是组合节点,则可以继续拥有子节点,如果是叶子节点,那么就终止了。

 叶子节点和组合节点可以有相同的操作,如上面代码中的operation()方法,但是叶子节点不具备add、remove以及getChild操作,如果你试图在叶子节点上调用这些方法就会抛出不支持的异常。组合节点可以添加子节点,因此组合节点实现了add、remove以及getChild等操作。组合节点持有一个节点的集合,在组合节点的operation()方法中通过遍历调用持有节点的operation()方法,就像是在递归遍历一样。通过这种方式Client客户端可以透明的访问节点对象,你可以在客户端中调用一个组合节点的operation()方法,也可以调用一个叶子节点的operation()方法,也就是说你根本不需要关心调用的是组合节点还是叶子节点,它们都可以进行相同的操作。  

![](https://img-blog.csdn.net/20180524014958374?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2x5YWJjMTIzNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)  

**菜单的例子**

 服务员需要打印菜单,如菜单的名称和价格,但是菜单既可以有子菜单组合,也可以有子菜单项,对于子菜单组合,它的下面又可能会有子菜单项,如饮料菜单和甜点菜单等会包含很多东西,而子菜单项就是一个具体的菜名,不会有子菜单了。现在要打印所有的菜单描述,我们用组合模式来实现这个功能:  

![](https://img-blog.csdn.net/20180524100344222?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2x5YWJjMTIzNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)  

实现代码:

/**

  • 抽象菜单组件

    */

public abstract class MenuComponent {

public void add(MenuComponent menu) {

    throw new UnsupportedOperationException();

}

public void remove(MenuComponent menu) {

    throw new UnsupportedOperationException();

}

public MenuComponent getChild(int i) {

    throw new UnsupportedOperationException();

}

public String getName() {

    throw new UnsupportedOperationException();

}

public double getPrice() {

    throw new UnsupportedOperationException();

}

public abstract void print();

}


/**

 * 菜单组件

 * 菜单组件有菜单名和子菜单,但没有价格,支持添加、删除和打印等操作

 */

public class Menu extends MenuComponent {

    private List<MenuComponent> menuList = new ArrayList<>();

    private String name;

    public Menu(String name) {

        this.name = name;

    }

    @Override

    public void add(MenuComponent menu) {

        menuList.add(menu);

    }

    @Override

    public void remove(MenuComponent menu) {

        menuList.remove(menu);

    }

    @Override

    public MenuComponent getChild(int i) {

        return menuList.get(i);

    }

    @Override

    public String getName() {

        return name;

    }

    @Override

    public void print() {

        System.out.println("--------");

        System.out.println(getName());

        //打印所有子菜单

        for (MenuComponent menu : menuList) {

             menu.print();

        }

        System.out.println("--------");

    }

}

/**

  • 菜单项

  • 菜单项拥有名称和价格,可以打印,但是不支持添加、删除等操作

    */

public class MenuItem extends MenuComponent {

private String name;

private double price;

public MenuItem(String name, double price) {

    this.name = name;

    this.price = price;

}

@Override

public String getName() {

    return name;

}

@Override