组合模式:允许将对象组合成树形结构来表现“整体/部分”层次结构。组合让客户用一致的方式处理个别对象和组合对象
特点:
- 树形结构表示对象组合
- 忽略对象组合和对象个体之间的差别,即相同的操作既可以作用于对象组合,也可以作用与对象个体
注意:
- 因为继承方法中,有些方法只有对叶子节点有意义,而有些方法只对非叶子节点有意义,我们可以将基类的方法默认实现为抛出UnsupportedOperationException,如果方法无意义,则无需修改默认继承就可以了
透明性:
- 组合模式以单一责任原则换取了透明性
- 通过让组件接口同时包含叶子节点和非叶子节点的操作,客户可以将叶子节点和非叶子节点一视同仁,客户不知道节点的类别
- 换取透明性的同时我们同样失去了一些安全性
举例:
实现菜单中的每一項可以是菜单也可以是菜单项
抽象基类包括叶子节点和非叶子节点的全部操作默认实现为Exception
1 public abstract class MenuComponent 2 { 3 //对一些方法进行了默认实现 4 public void add(MenuComponent menuComponent) 5 { 6 throw new UnsupportedOperationException(); 7 } 8 public void remove(MenuComponent menuComponent) 9 { 10 throw new UnsupportedOperationException(); 11 } 12 public MenuComponent getChild(int i) 13 { 14 throw new UnsupportedOperationException(); 15 } 16 public String getName() 17 { 18 throw new UnsupportedOperationException(); 19 } 20 public String getDescription() 21 { 22 throw new UnsupportedOperationException(); 23 } 24 public double getPrice() 25 { 26 throw new UnsupportedOperationException(); 27 } 28 public boolean isVegetarian() 29 { 30 throw new UnsupportedOperationException(); 31 } 32 public void print() 33 { 34 throw new UnsupportedOperationException(); 35 } 36 }
菜单项实现,即叶子节点实现
1 public class MenuItem extends MenuComponent 2 { 3 String name; 4 String description; 5 boolean vegetarian; 6 double price; 7 8 public MenuItem(String name, String description, boolean vegetarian,double price) 9 { 10 this.name = name; 11 this.description = description; 12 this.vegetarian = vegetarian; 13 this.price = price; 14 } 15 public String getName() 16 { 17 return name; 18 } 19 public String getDescription() 20 { 21 return description; 22 } 23 public double getPrice() 24 { 25 return price; 26 } 27 public boolean isVegetarian() 28 { 29 return vegetarian; 30 } 31 public void print() 32 { 33 System.out.print(" " + getName()); 34 if (isVegetarian())//素食 35 { 36 System.out.print("(v)"); 37 } 38 System.out.println(", " + getPrice()); 39 System.out.println(" -- " + getDescription()); 40 } 41 }
菜单实现,即非叶子节点的实现:
1 public class Menu extends MenuComponent 2 { 3 ArrayList<MenuComponent> menuComponents = new ArrayList<MenuComponent>(); 4 String name; 5 String description; 6 7 public Menu(String name, String description) 8 { 9 this.name = name; 10 this.description = description; 11 } 12 13 public void add(MenuComponent menuComponent) 14 { 15 menuComponents.add(menuComponent); 16 } 17 18 public void remove(MenuComponent menuComponent) 19 { 20 menuComponents.remove(menuComponent); 21 } 22 23 public MenuComponent getChild(int i) 24 { 25 return menuComponents.get(i); 26 } 27 28 public String getName() 29 { 30 return name; 31 } 32 33 public String getDescription() 34 { 35 return description; 36 } 37 38 public void print() 39 { 40 System.out.print(" " + getName()); 41 System.out.println(", " + getDescription()); 42 System.out.println("---------------------"); 43 44 Iterator iterator = menuComponents.iterator(); 45 while (iterator.hasNext()) 46 { 47 MenuComponent menuComponent = (MenuComponent) iterator.next(); 48 menuComponent.print(); 49 } 50 } 51 }
组合迭代器:
1 public class CompositeIterator implements Iterator<MenuComponent> { 2 3 Stack<Iterator<MenuComponent>> stack = new Stack<Iterator<MenuComponent>>(); 4 5 6 public CompositeIterator(Iterator<MenuComponent> iterator) { 7 stack.push(iterator); 8 } 9 10 public boolean hasNext() { 11 if (stack.empty()) { 12 return false; 13 } else { 14 Iterator<MenuComponent> iterator = (Iterator<MenuComponent>)stack.peek(); 15 if (!iterator.hasNext()) { 16 stack.pop(); 17 return hasNext(); //递归调用 18 } else { 19 return true; 20 } 21 } 22 } 23 24 public MenuComponent next() { 25 if (hasNext()) { 26 Iterator<MenuComponent> iterator = (Iterator<MenuComponent>)stack.peek(); 27 MenuComponent component = (MenuComponent)iterator.next(); 28 if (component instanceof Menu) { 29 stack.push(component.createIterator()); 30 } 31 return component; 32 } else { 33 return null; 34 } 35 } 36 37 public void remove() { 38 throw new UnsupportedOperationException(); 39 } 40 41 }