//调用所有子节点的操作
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
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/147230.html