introduction:
组合模式:
允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
组合模式让我们能用树形方式创建对象的结构,树里面包含了组合及个别的对象。
使用组合结构,我们能把相同的操作运用在组合和个别对象上。换句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。
为了保证透明性,组合内所有的对象都必须实现相同的接口,这意味着对象具备一些没有意义的方法调用。
对于没哟意义的方法我们可以返回null或false,甚至可以抛出一个异常
demo: 以迭代器模式一样,模拟一天三餐,现在的情况与迭代器不同的是:我们现在可以组合菜单,顾名思义,我们现在一个菜单项可以出现在不同的菜单中,同样,一个菜单也可能出现在另一个菜单中,总而言之,现在的菜单结构变成了一个树形结构。树形结构的叶子节点相当于一个个菜单项,每一个中间节点相当于一个菜单。
description:
在组合模式中,所有的对象都继承于一个公共接口,公共接口中提供所有整体和部分分别需要实现的方法。
Component.java
public abstract class Component {
public void add(Component component){
throw new UnsupportedOperationException();
}
public void remove(Component component){
throw new UnsupportedOperationException();
}
public void print(){
throw new UnsupportedOperationException();
}
public void getName(String name){
throw new UnsupportedOperationException();
}
public void getPrice(Double price){
throw new UnsupportedOperationException();
}
public Component getChild(int i){
throw new UnsupportedOperationException();
}
public Iterator<Component> createIterator(){
throw new UnsupportedOperationException();
}
}
对于叶子节点只需要实现公共接口中有用的方法
Leaf.java
/**
* 该类为一个个别对象,也就是组合模式中所说的部分
* 该类只需要重写公共接口中的一部分方法(因为有些方法在这个类中不适用)
*/
public class Leaf extends Component{
private String name;
private Double price;
/**
* @param name
* @param price
*/
public Leaf(String name, Double price) {
this.name = name;
this.price = price;
}
@Override
public void getName(String name) {
this.name = name;
}
@Override
public void getPrice(Double price) {
this.price = price;
}
@Override
public void print() {
System.out.println("--- leaf ---");
System.out.print(name+"---");
System.out.println(price);
}
@Override
public Iterator<Component> createIterator() {
return new NullIterator();
}
}
空迭代器:实际上什么也没有做,可是这样做不会返回null
NullIterator.java
public class NullIterator implements Iterator<Component>{
@Override
public boolean hasNext() {
return false;
}
@Override
public Component next() {
return null;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
对于组合节点同样只需要实现公共接口中有用的接口就可以了
Composite.java/**
* 该类为一个组合对象,也就是我们所说的整体
* 同样该类只需要重写公共接口中一部分方法
*/
public class Composite extends Component{
private ArrayList<Component> components = new ArrayList<Component>();
private String name;
private Double price;
/**
* @param name
* @param price
*/
public Composite(String name, Double price) {
this.name = name;
this.price = price;
}
@Override
public void add(Component component) {
components.add(component);
}
@Override
public void remove(Component component) {
components.remove(component);
}
@Override
public void print() {
System.out.println("--- Composite ---");
System.out.print(name+" --- ");
System.out.println(price+" --- ");
Iterator<Component> componentIterator = components.iterator();
while(componentIterator.hasNext()){
componentIterator.next().print();
}
}
@Override
public Iterator<Component> createIterator() {
return new CompositeIterator(components.iterator());
}
}
下面这段代码是难点,下面实现的是一个外部迭代器,所以必须维护它在遍历中的位置,以便外部客户可以通过hasNext()和next()来驱动遍历。
CompositeIterator.java
public class CompositeIterator implements Iterator<Component>{
/**
* 将所有的迭代器都存储在栈中
*/
private Stack<Iterator<Component>> stack = new Stack<Iterator<Component>>();
public CompositeIterator(Iterator<Component> componentIterator){
stack.push(componentIterator);
}
/**
*
*/
@Override
public boolean hasNext() {
if(stack.isEmpty()){
return false;
}else{
Iterator<Component> iterator = stack.peek();
if(!iterator.hasNext()){
stack.pop();
return hasNext();
}else{
return true;
}
}
}
@Override
public Component next() {
if(hasNext()){
Iterator<Component> iterator = stack.peek();
Component component = iterator.next();
if(component instanceof Composite){
stack.push(component.createIterator());
}
return component;
}
return null;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
最后,测试以上代码:
Test.java
public class Test {
public static void main(String[] args) {
Component breakfast = new Composite("早餐",5.00);
Component lunch = new Composite("午餐",15.00);
Component diner = new Composite("晚餐",10.00);
Component drink = new Composite("饮料",3.00);
breakfast.add(new Leaf("面包",2.00));
breakfast.add(new Leaf("牛奶",3.00));
lunch.add(new Leaf("带鱼",5.00));
lunch.add(new Leaf("臭豆腐",3.00));
lunch.add(new Leaf("茄子烧肉",4.00));
lunch.add(drink);
diner.add(new Leaf("红烧鳊鱼",5.00));
diner.add(new Leaf("鸡蛋菜汤",3.00));
diner.add(new Leaf("青菜",2.00));
diner.add(lunch);
drink.add(new Leaf("冰红茶",3.00));
Component components = new Composite("一天三餐",30.00);
components.add(breakfast);
components.add(lunch);
components.add(diner);
Client c = new Client(components);
c.printComponent();
}
}
输出结果:
--- Composite ---
一天三餐 --- 30.0 ---
--- Composite ---
早餐 --- 5.0 ---
--- leaf ---
面包---2.0
--- leaf ---
牛奶---3.0
--- Composite ---
午餐 --- 15.0 ---
--- leaf ---
带鱼---5.0
--- leaf ---
臭豆腐---3.0
--- leaf ---
茄子烧肉---4.0
--- Composite ---
饮料 --- 3.0 ---
--- leaf ---
冰红茶---3.0
--- Composite ---
晚餐 --- 10.0 ---
--- leaf ---
红烧鳊鱼---5.0
--- leaf ---
鸡蛋菜汤---3.0
--- leaf ---
青菜---2.0
--- Composite ---
午餐 --- 15.0 ---
--- leaf ---
带鱼---5.0
--- leaf ---
臭豆腐---3.0
--- leaf ---
茄子烧肉---4.0
--- Composite ---
饮料 --- 3.0 ---
--- leaf ---
冰红茶---3.0