1.组合模式
允许将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象(叶子接点)及对象组合(中间节点)。
组合模式关键在于无论是个体对象还是组合对象都实现了相同的接口或都是同一个抽象类的子类。
2.应用场景
1.你想表示对象的部分-整体层次结构
2.你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
3.组合模式的三个角色
①抽象组件(Component):是一个接口(抽象类),该接口定义了个体对象和组合
对象需要实现的关于操作其子节点的方法或用于操作其自身的方法。
②Composite节点:实现Component接口类的实例,同时可以含有其它Composite
节点或Leaf节点的引用
③Leaf节点:实现Component接口类的实例,不可以包含其它Composite
节点或Leaf节点的引用
4.组合模式经典UML类图
代码示例:
场景:
1.我们需要某种树形结构,可以容纳菜单、子菜单和菜单项;
2.我们需要确定能够在每个菜单的各个项之间游走,而且至少像用迭代器一样方便;
3.我们能够弹性在菜单项之间游走,如:可以只遍历甜点菜单,或者可以遍历餐厅整个菜单
1.抽象组件(Component):是一个接口(抽象类),该接口定义了个体对象和组合,对象需要实现的关于操作其子节点的方法或用于操作其自身的方法。
package jdp.com;
/**
* @ClassName: MenuComponent
* @Description:抽象组件
* @author: lsh
* @date: 2019年6月22日
*/
public abstract class MenuComponent {
public void add(MenuComponent muComponent) {
throw new UnsupportedOperationException();
}
public void remove(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public MenuComponent getChild(int i) {
throw new UnsupportedOperationException();
}
public String getName() {
throw new UnsupportedOperationException();
}
public String getDescription() {
throw new UnsupportedOperationException();
}
public double getPrice() {
throw new UnsupportedOperationException();
}
public boolean isVegetarian() {
throw new UnsupportedOperationException();
}
public void print() {
throw new UnsupportedOperationException();
}
}
2.Composite节点:实现Component接口类的实例,同时可以含有其它Composite
节点或Leaf节点的引用
package jdp.com;
import java.util.ArrayList;
import java.util.Iterator;
/**
* @ClassName: Menu
* @Description:Composite节点,组合对象,组合菜单
* @author: lsh
* @date: 2019年6月22日
*/
public class Menu extends MenuComponent {
ArrayList menuComponents = new ArrayList();
String name;
String description;
public Menu(String name, String description) {
this.name = name;
this.description = description;
}
public void add(MenuComponent muComponent) {
menuComponents.add(muComponent);
}
public void remove(MenuComponent menuComponent) {
menuComponent.remove(menuComponent);
}
public MenuComponent getChild(int i) {
return (MenuComponent)menuComponents.get(i);
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public void print() {
System.out.print("\n" + getName());
System.out.println("," + getDescription());
System.out.println("---------------------");
Iterator iterator = menuComponents.iterator();
// 迭代器
while (iterator.hasNext()) {
MenuComponent menuComponent = (MenuComponent)iterator.next();
menuComponent.print();
}
}
}
3.Leaf节点:实现Component接口类的实例,不可以包含其它Composite节点或Leaf节点的引用
package jdp.com;
/**
* @ClassName: MenuItem
* @Description: Leaf节点,个别对象,为菜单项
* @author: lsh
* @date: 2019年6月22日
*/
public class MenuItem extends MenuComponent {
String name;
String description;
boolean vegetarian;
double price;
public MenuItem(String name,
String description,
boolean vegetarian,
double price) {
this.name = name;
this.description = description;
this.vegetarian = vegetarian;
this.price = price;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public boolean isVegetarian() {
return vegetarian;
}
public double getPrice() {
return price;
}
public void print() {
System.out.print(" " + getName());
if (isVegetarian()) {
System.out.print("V");
}
System.out.println("," + getPrice() + " ---" + getDescription());
}
}
4.Client(组合菜单)
package jdp.com.test;
import jdp.com.Menu;
import jdp.com.MenuComponent;
import jdp.com.MenuItem;
import jdp.com.NewMenu;
/**
* @ClassName: TestApp
* @Description:TODO
* @author: lsh
* @date: 2019年6月22日
*/
public class TestApp {
public static void main(String[] args) {
// 创建所有菜单
MenuComponent breakfastMenu = new Menu("Breakfast Menu", "Breakfast");
MenuComponent dinerMenu = new Menu("Diner Menu", "Lunch");
MenuComponent cafeMenu = new Menu("CAFE Menu", "Dinner");
MenuComponent dessertMenu = new Menu("DeSSERT Menu", "Dessert"); // 甜品菜单
// 将上述菜单组合
MenuComponent allMenu = new Menu("All Menu", "All menus");
allMenu.add(breakfastMenu);
allMenu.add(dinerMenu);
allMenu.add(cafeMenu);
// 分别加入菜单项
breakfastMenu.add(new MenuItem("1", "scranbled eggs and toast", true, 2.99));
breakfastMenu.add(new MenuItem("2", "scranbled eggs and toast", false, 3.99));
breakfastMenu.add(new MenuItem("3", "scranbled eggs and toast", true, 4.99));
dinerMenu.add(new MenuItem("4", "scranbled eggs and toast", true, 5.99));
dinerMenu.add(new MenuItem("5", "scranbled eggs and toast", false, 3.29));
dinerMenu.add(new MenuItem("6", "scranbled eggs and toast", false, 3.05));
dessertMenu.add(new MenuItem("7", "scranbled eggs and toast", false, 3.05));
dessertMenu.add(new MenuItem("8", "scranbled eggs and toast", true, 3.05));
dinerMenu.add(dessertMenu);
cafeMenu.add(new MenuItem("10", "scranbled eggs and toast", true, 3.05));
cafeMenu.add(new MenuItem("11", "scranbled eggs and toast", false, 3.05));
NewMenu newMenu = new NewMenu(allMenu);
newMenu.printMenu();
}
}
package jdp.com;
/**
* @ClassName: NewMenu
* @Description:TODO
* @author: lsh
* @date: 2019年6月22日
*/
public class NewMenu {
MenuComponent newMenu;
public NewMenu(MenuComponent newMenu) {
this.newMenu = newMenu;
}
public void printMenu() {
newMenu.print();
}
}
6.执行结果: