组合模式允许你将对象组合成树形状结构来表现”整体/部分“层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
阅读组合模式之前建议先阅读迭代器模式。
在迭代器模式中,Waitress类中指管理了PancakeHouseMenu和DinerMenu,如果现在有许多菜单并且菜单可以有子菜单,该如何管理?
那么就是使用组合模式。
java代码
// 顶级容器类,包含菜单和菜单项的方法
public abstract class MenuComponent {
public float getPrice() {
throw new UnsupportedOperationException("operate is not support");
}
public String getName() {
throw new UnsupportedOperationException("operate is not support");
}
public void print() {
throw new UnsupportedOperationException("operate is not support");
}
public void add(MenuComponent component) {
throw new UnsupportedOperationException("operate is not support");
}
}
// 菜单项
public class MenuItem extends MenuComponent {
private String name;
private float price;
public MenuItem(String name, float price) {
this.name = name;
this.price = price;
}
@Override
public float getPrice() {
return price;
}
@Override
public String getName() {
return name;
}
@Override
public void print() {
System.out.println("MenuItem{name='" + name + "'" + ", price=" + price + '}');
}
}
// 菜单
public class Menu extends MenuComponent {
private String name;
private List<MenuComponent> components;
public Menu(String name) {
this.name = name;
components = new ArrayList<>();
}
@Override
public String getName() {
return name;
}
@Override
public void add(MenuComponent component) {
components.add(component);
}
@Override
public void print() {
System.out.println(name);
Iterator<MenuComponent> iterator = components.iterator();
while (iterator.hasNext()){
iterator.next().print();
}
}
}
// 服务员
public class Waitress {
private MenuComponent component;
public Waitress(MenuComponent component) {
this.component = component;
}
public void printMenu(){
component.print();
}
}
// 测试类
public class Test {
public static void main(String[] args) {
new Test().test();
}
private void test() {
// 根菜单
MenuComponent root = new Menu("root");
// 一级菜单
MenuComponent pancakeHouseMenu = new Menu("pancakeHouseMenu");
MenuComponent dinerMenu = new Menu("dinerMenu");
MenuComponent coffeeMenu = new Menu("coffeeMenu");
// 菜单项
pancakeHouseMenu.add(new MenuItem("K&B's Pancake", 2.99f));
pancakeHouseMenu.add(new MenuItem("Regular Pancake", 2.59f));
pancakeHouseMenu.add(new MenuItem("Blueberry Pancake", 3.49f));
dinerMenu.add(new MenuItem("BLT", 2.99f));
dinerMenu.add(new MenuItem("Soup", 3.29f));
dinerMenu.add(new MenuItem("Hot dog", 3.05f));
coffeeMenu.add(new MenuItem("Dark Roast Coffee", 0.99f));
coffeeMenu.add(new MenuItem("Decaf Coffee", 1.05f));
coffeeMenu.add(new MenuItem("Espresso Coffee", 1.99f));
// 一级菜单加入根菜单
root.add(pancakeHouseMenu);
root.add(dinerMenu);
root.add(coffeeMenu);
// 二级菜单
MenuComponent dessertMenu = new Menu("dessertMenu");
// 菜单项
dessertMenu.add(new MenuItem("Apple pie", 1.32f));
dessertMenu.add(new MenuItem("Strawberry pie", 1.55f));
// 二级菜单加入餐厅
dinerMenu.add(dessertMenu);
Waitress waitress = new Waitress(root);
waitress.printMenu();
}
}
注:
- 组合模式让我们能用树形方式创建对象的结构,树里面包含组合以及个别的对象。
- 使用组合结构,我们能把相同的操作应用在组合和个别对象上。换句话说,在大多说情况下,我们可以忽略对象组合和个别对象之间的差别。
外部迭代
上面代码展示的是内部的迭代,如果现在服务员需要筛选出价格低于2元的食品,那么我们就需要让服务员做外部的迭代
java代码
// 组合迭代器,可能比较难理解
public class CompositeIterator implements Iterator<MenuComponent> {
private Stack<Iterator<MenuComponent>> stack;
public CompositeIterator(Iterator<MenuComponent> iterator) {
stack = new Stack<>();
stack.push(iterator);
}
@Override
public MenuComponent next() {
Iterator<MenuComponent> iterator = stack.peek();
MenuComponent component = iterator.next(); // 这里调用的是List的next方法,并不是递归
if (component instanceof Menu) {
stack.push(component.iterator());
}
return component;
}
@Override
public boolean hasNext() {
if (stack.isEmpty()) {
return false;
} else {
Iterator<MenuComponent> iterator = stack.peek();
if (iterator.hasNext()) { // 这里调用的是List的hasNext方法,并不是递归
return true;
} else {
stack.pop();
return hasNext(); // 递归
}
}
}
}
// 空迭代器
public class NullIterator implements Iterator {
@Override
public boolean hasNext() {
return false;
}
@Override
public Object next() {
return null;
}
}
// 顶级容器类,包含菜单和菜单项的方法
public abstract class MenuComponent {
public float getPrice() {
throw new UnsupportedOperationException("operate is not support");
}
public boolean lessThen(float price) {
throw new UnsupportedOperationException("operate is not support");
}
public String getName() {
throw new UnsupportedOperationException("operate is not support");
}
public void print() {
throw new UnsupportedOperationException("operate is not support");
}
public Iterator<MenuComponent> iterator() {
throw new UnsupportedOperationException("operate is not support");
}
public void add(MenuComponent component) {
throw new UnsupportedOperationException("operate is not support");
}
}
// 菜单项
public class MenuItem extends MenuComponent {
private String name;
private float price;
public MenuItem(String name, float price) {
this.name = name;
this.price = price;
}
@Override
public float getPrice() {
return price;
}
@Override
public boolean lessThen(float price) {
return this.price < price;
}
@Override
public String getName() {
return name;
}
@Override
public Iterator<MenuComponent> iterator() {
return new NullIterator();
}
@Override
public void print() {
System.out.println("MenuItem{name='" + name + "'" + ", price=" + price + '}');
}
}
// 菜单
public class Menu extends MenuComponent {
private String name;
private List<MenuComponent> components;
public Menu(String name) {
this.name = name;
components = new ArrayList<>();
}
@Override
public String getName() {
return name;
}
@Override
public void add(MenuComponent component) {
components.add(component);
}
@Override
public Iterator<MenuComponent> iterator() {
return new CompositeIterator(components.iterator());
}
@Override
public void print() {
System.out.println(name);
Iterator<MenuComponent> iterator = components.iterator();
while (iterator.hasNext()) {
iterator.next().print();
}
}
}
// 服务员
public class Waitress {
private MenuComponent component;
public Waitress(MenuComponent component) {
this.component = component;
}
public void printMenuPriceLessThen(float price) {
Iterator<MenuComponent> iterator = component.iterator();
MenuComponent component;
while (iterator.hasNext()) {
component = iterator.next();
if (component instanceof MenuItem && component.lessThen(price)) {
component.print();
}
}
}
public void printMenu() {
component.print();
}
}
// 测试类
public class Test {
public static void main(String[] args) {
new Test().test();
}
private void test() {
// 根菜单
MenuComponent root = new Menu("root");
// 一级菜单
MenuComponent pancakeHouseMenu = new Menu("pancakeHouseMenu");
MenuComponent dinerMenu = new Menu("dinerMenu");
MenuComponent coffeeMenu = new Menu("coffeeMenu");
// 菜单项
pancakeHouseMenu.add(new MenuItem("K&B's Pancake", 2.99f));
pancakeHouseMenu.add(new MenuItem("Regular Pancake", 2.59f));
pancakeHouseMenu.add(new MenuItem("Blueberry Pancake", 3.49f));
dinerMenu.add(new MenuItem("BLT", 2.99f));
dinerMenu.add(new MenuItem("Soup", 3.29f));
dinerMenu.add(new MenuItem("Hot dog", 3.05f));
coffeeMenu.add(new MenuItem("Dark Roast Coffee", 0.99f));
coffeeMenu.add(new MenuItem("Decaf Coffee", 1.05f));
coffeeMenu.add(new MenuItem("Espresso Coffee", 1.99f));
// 一级菜单加入根菜单
root.add(pancakeHouseMenu);
root.add(dinerMenu);
root.add(coffeeMenu);
// 二级菜单
MenuComponent dessertMenu = new Menu("dessertMenu");
// 菜单项
dessertMenu.add(new MenuItem("Apple pie", 1.32f));
dessertMenu.add(new MenuItem("Strawberry pie", 1.55f));
// 二级菜单加入餐厅
dinerMenu.add(dessertMenu);
Waitress waitress = new Waitress(root);
waitress.printMenuPriceLessThen(2);
}
}
注:
- 现在服务员有更多的权限了
参考文章
1. Head First 设计模式