本文出自 http://blog.csdn.net/shuangde800
认识组合模式
上一篇中,我们可以用迭代器来实现遍历一个集合(数组,ArrayList, Vector, HashTable等)。
假设有这样一种集合结构:餐厅里有一份菜单,菜单里面还有子菜单,其实就是一个树形的结构
那么,之前的迭代器就不能用了。
我们需要新的设计:
1. 需要某种树形结构,可以容纳菜单,子菜单和菜单项
2. 需要确定能够在每个菜单的各个项之间游走,而且至少要像现在用迭代器一样方便
3. 我们也需要更有弹性地在菜单之间游走。比方说,可能只需要遍历甜点菜单,或者可以遍历餐厅的整个菜单
定义组合模式
组合模式允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合
有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
组合模式让你可以优化处理递归或分级数据结构。有许多关于分级数据结构的例子,使得组合模式非常有用武之地。关于分级数据结构的一个普遍性的例子是你每次使用电脑时所遇到的:文件系统。文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,那么你可以使用组合模式Composite。
以嵌套菜单为例,这个模式能够创建一个树形结构,在同一个结构中处理嵌套菜单和菜单项组。通过将菜单和项放在相同的结构中,我们创建了一个“整体/部分”层次结构,即由菜单和菜单项组成的对象树。但是可以将它视为一个整体,像是一个丰富的大菜单。
一旦有了丰富的“大菜单”,我们就可以用这个模式来“统一处理个别对象和组合对象”。
这意味着,如果我们有了一个树形结构的菜单,子菜单和可能还带有菜单项的子菜单,那么任何一个菜单都是一种“组合”。因为它既可以包含其他菜单,也可以包含菜单项。我们可以忽略对象组合和个别对象之间的差别。
使用组合模式,只要写出简单的代码,就能够对整个菜单结构应用相同的操作!
利用组合设计菜单
1. 实现菜单组件
// 菜单组件的抽象类
// 菜单组件的角色是为叶子节点和组合节点提供一个共同的接口
// 所有的组件都必须实现MenuComponent接口
// 但是叶节点和在组合节点的角色不同,所以有些方法可能不适合某些节点
// 面对这种情况,最好抛出运行时异常
public abstract class MenuComponent {
public void add(MenuComponent menuComponent) {
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. 实现菜单项
// 这是组合类图的叶类,这里是菜单项
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 double getPrice() {
return price;
}
public boolean isVegetarian() {
return vegetarian;
}
// 这里和之前的实现不一样
// 我们覆盖了print()方法
// 对菜单项来说,此方法会打印出完整的菜单条目
// 包括名字,描述,价格等
public void print() {
System.out.print(" " + getName());
if (isVegetarian()) {
System.out.print("(v)");
}
System.out.println(", " + getPrice());
System.out.println(" -- " + getDescription());
}
}
3. 实现组合菜单
public class Menu extends MenuComponent {
// 菜单可以有任意数目的儿子
// 且这些儿子必须属于MenuComonent类型
// 在内部ArrayList里记录它们
ArrayList menuComponents = new ArrayList();
String name;
String description;
// 和菜单项不一样,这里只描述菜单名
public Menu(String name, String description) {
this.name = name;
this.description = description;
}
// 这个方法添加一个子菜单或者菜单项
public void add(MenuComponent menuComponent) {
menuComponents.add(menuComponent);
}
// 删除一个子菜单或者菜单项
public void remove(MenuComponent menuComponent) {
menuComponents.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();
}
}
}
组合迭代器
组合模式的迭代器需要用递归来实现
public class CompositeIterator implements Iterator {
Stack stack = new Stack();
// 将我们需要遍历的顶层组合的迭代器传入
// 放进一个栈数据结构中
public CompositeIterator(Iterator iterator) {
stack.push(iterator);
}
// 当客户想要取得下一个元素的时候
// 我们先调用hashNext()来判断是否还有下一个元素
public Object next() {
if (hasNext()) {
Iterator iterator = (Iterator) stack.peek();
MenuComponent component = (MenuComponent) iterator.next();
if (component instanceof Menu) {
// 如果元素是菜单,我们有了另一个需要被包含进遍历中的组合
// 将它放进栈中
stack.push(component.createIterator());
}
return component;
} else {
return null;
}
}
public boolean hasNext() {
if (stack.empty()) { //如果栈空了,说明没有下一个元素了
return false;
} else {
Iterator iterator = (Iterator) stack.peek();
if (!iterator.hasNext()) {
stack.pop();
return hasNext();
} else {
return true;
}
}
}
// 不支持删除
public void remove() {
throw new UnsupportedOperationException();
}
}
空迭代器
先要一个组合迭代器,那么每个组件都要加上createIterator()方法。
在菜单中实现:
public class Menu extends MenuComponent {
// 其它部分代码不需要修改
public Iterator createIterator() {
return new CompositeIterator(menuComponents.iterator()) ;
}
}
但是在菜单项中要怎样实现呢?我们知道菜单项是叶子节点,没有什么可以遍历了。
有两种选择:
选择一: 返回null
我们可以让createItrerator()方法返回null,但是如果这样做,我们的客户代码就要条件语句来判断返回值是否为null
选择二:返回一个迭代器,这个迭代器的hasNext()永远返回false
这个方法显然更好,客户就不必担心是否为null了。
public class NullIterator implements Iterator {
public Object next() {
return null;
}
public boolean hasNext() {
return false;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
菜单项实现createIterator()方法
public class MenuItem extends MenuComponent {
// 其它部分代码不需要修改
public Iterator createIterator() {
return new NullIterator(); // 返回空迭代器
}
}
分享到:
相关推荐
学习笔记5:数据预处理与数据挖掘十大经典算法.docx学习笔记5:数据预处理与数据挖掘十大经典算法.docx学习笔记5:数据预处理与数据挖掘十大经典算法.docx学习笔记5:数据预处理与数据挖掘十大经典算法.docx学习笔记...
前端学习笔记整理:HTML, CSS, JavaScript, Web 性能优化, 工具, 框架, 资源 前端学习笔记整理:HTML, CSS, JavaScript, Web 性能优化, 工具, 框架, 资源 前端学习笔记整理:HTML, CSS, JavaScript, Web 性能优化, ...
Activiti 学习笔记13:分配组任务
设计模式学习笔记,分析了GOF的23种模式和类设计的原则
Java设计模式学习笔记
我收集的设计模式的学习笔记,采用pdf格式,便于收藏和查看
各个模式都有详细的例子C#学习笔记,打开就知道了
STM32 F103C8T6学习笔记13:AHT10温湿度传感器模块.rar
HeadFirst设计模式学习笔记比较全面详细地讲解了13个设计模式,有利于大家更好的学习HeadFirst设计模式,希望亲们会喜欢~~~
总结了java开发中的21种设计模式,详解和例子,带书签的pdf格式,方便阅读!
设计模式学习笔记.ppt 自己写的一点学习笔记。
VC学习笔记1:按钮的使能与禁止 VC学习笔记2:控件的隐藏与显示 VC学习笔记3:改变控件的大小和位置 VC学习笔记4:什么时候设定视中控件的初始尺寸? ......
设计模式学习笔记,总共23个设计模式,还有几个设计原则
23种设计模式学习笔记及源码,全部原创 欢迎提出意见和建议
Head First 设计模式学习笔记。更多内容请参见文章内容。
学习Java设计模式的笔记,标注了其中重要的要点,如果有需要的小伙伴,自行下载哦
资源名称:设计模式C 学习笔记资源目录:【】设计模式C 学习笔记源代码【】设计模式C 学习笔记目录【】设计模式C 学习笔记(1)【】设计模式C 学习笔记(2)【】设计模式C 学习笔记(3)【】设计模式C 学习笔记(4)...
设计模式学习笔记--Flyweight享元模式.docx设计模式学习笔记--Flyweight享元模式.docx设计模式学习笔记--Flyweight享元模式.docx设计模式学习笔记--Flyweight享元模式.docx设计模式学习笔记--Flyweight享元模式.docx
代理模式学习笔记、单例模式学习笔记、命令模式、原型模式、模式特点总结。 为个人对设计模式的理解,如果有理解不一致的不要砸砖啊
1) 内容包括: 设计模式七大原则(单一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式:单例模式(8种...