问题汇总
- 迭代器定义和作用
迭代器遍历一个聚合物,并将其封装成另一个对象。 - 迭代器适用场景
- 迭代器模式的结构和实现方法
- 组合模式定义和作用以及适用场景
适用于“整体/部分”的关系结构,用于统一处理所有对象(不分节点还是叶子)。 - 组合模式结构和实现的两种方案。
- 树结构。
- 将所有功能都加入到Component中。或者将不同功能通过接口来赋予不同对象。其间的思想就是透明度和安全性的平衡。
- 迭代器设计原则:一个类一个功能。
- 观察者和状态模式的区别
- 观察者:当状态改变时,通知一组对象。
- 状态:当状态改变时,让一个对象改变行为。
问题答案日后补充
1-迭代器模式
1-定义:
提供一种方法能够顺序访问聚合对象中的元素,而不需要暴露内部的表示。
2-结构:
- 聚合接口(Aggregate)-提供createIterator方法
- ConcreteAggregate-实现聚合接口中的createIterator方法
- Iterator(迭代器接口)-提供hasNext\next等方法
- ConcreteIterator(具体迭代器)-实现接口的方法
使用
通过ConcreteAggregate的createIterator()方法获得具体迭代器。使用具体迭代器中的hasNext()\next()遍历所有元素。
Iterator的古老版本是Enumeration,新旧版本之间的兼容可以用
Adapter Pattern
3-设计原则:
一个类应该只有一个引起变化的原因:一个责任只指派给一个类
高内聚:一个类只支持一组相关的功能。
- Hashtable是由两组数据组成:key和values。我们可以单独取出values调用其中的iterator()来获取迭代器。
4-Java5遍历集合而不用显式Iterator
for(Object obj : collection){
...
}
5-实例:餐厅
一个服务员有几个餐厅的菜单,各个餐厅的菜品组成方式都不相同。这里需要通过迭代器在不了解餐厅菜单内部细节的情况下,遍历所有的菜品。这里按照上面的结构,分为几个部分:菜品MenuItem,菜单接口Menu, 具体餐厅菜单DinerMenu等等,迭代器。
1-MenuItem
包含菜名和单价
public class MenuItem {
String name;
int price;
public MenuItem(String name,int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
2-Menu
所有餐厅的菜单都实现Menu接口,并且实现了createIterator()方法用于获取迭代器。
public interface Menu {
public Iterator createIterator();
}
public class DinerMenu implements Menu{
MenuItem menuItems[] = new MenuItem[] {new MenuItem("diner1", 10)
, new MenuItem("diner2", 14)
, new MenuItem("diner3", 7)};
@Override
public Iterator createIterator() {
return new DinerMenuIterator(menuItems);
}
}
public class PancakeHouseMenu implements Menu{
ArrayList<MenuItem> menuItems = new ArrayList<>();
public PancakeHouseMenu() {
menuItems.add(new MenuItem("pancake1", 23));
menuItems.add(new MenuItem("pancake2", 13));
menuItems.add(new MenuItem("pancake3", 45));
}
@Override
public Iterator createIterator() {
return menuItems.iterator();
}
}
public class CafeMenu implements Menu{
Hashtable menuItems = new Hashtable<>();
public CafeMenu() {
MenuItem menuItem = new MenuItem("cafe1", 37);
menuItems.put(menuItem.getName(), menuItem);
menuItem = new MenuItem("cafe2", 87);
menuItems.put(menuItem.getName(), menuItem);
menuItem = new MenuItem("cafe3", 23);
menuItems.put(menuItem.getName(), menuItem);
}
@Override
public Iterator createIterator() {
//返回HashTable的迭代器
return menuItems.values().iterator();
}
}
3-Iterator
/**
* DinerMenu的迭代器:DinerMenu中数据用数组存储,需要实现该迭代器
* */
public class DinerMenuIterator implements Iterator{
MenuItem menuItems[];
int position = 0;
public DinerMenuIterator(MenuItem menuItems[]) {
this.menuItems = menuItems;
}
public boolean hasNext() {
if(position >= menuItems.length || menuItems[position] == null) {
return false;
}else {
return true;
}
}
@Override
public Object next() {
MenuItem menuItem = menuItems[position];
position++;
return menuItem;
}
}
4-服务员和测试
服务员遍历菜单,通过菜单的迭代器显示出所有菜品的菜名和单价。
public class Waitress {
ArrayList<Menu> menuList = new ArrayList<>();//存菜单
public Waitress() {
}
//添加菜单
public void addMenu(Menu menu){
menuList.add(menu);
}
/**--------------------------------------------
* 便利所有菜单,并且将菜单内容通过Iterator显示出来
* -------------------------------------------*/
public void printMenu() {
for(int i = 0; i < menuList.size(); i++) {
Menu menu = menuList.get(i);
Iterator iterator = menu.createIterator();
printMenu(iterator);
}
}
//根据迭代器打印菜单内容
private void printMenu(Iterator iterator) {
while(iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.println("name:"+menuItem.getName()+" price:"+menuItem.getPrice());
}
}
}
测试:
public class Test {
public static void main(String[] args) {
Waitress waitress = new Waitress();
waitress.addMenu(new CafeMenu());
waitress.addMenu(new PancakeHouseMenu());
waitress.addMenu(new DinerMenu());
waitress.printMenu();
}
}
2-组合模式(Composite Pattern)
如果上面实例中DinerMenu中某个菜品是另一个餐厅的菜单,这该如何处理?因为DinerMenu中存储的数据是MenuItem,是无法和Menu一起处理的。这就需要组合模式。
1-定义
允许你将对象组合成树形结构来构成“整体/部分”的层次结构。组合能让客户一致地处理单一对象和对象组合。
2-结构
类似于树的结构,有节点和叶子节点。但是系统在出的时候把叶子节点看做没有分支的节点。
1. Compoent(组件)-包含叶子节点和节点的所有操作。
2. Composite(组合,节点,extends Component)-实现属于节点的操作
3. Leaf(叶子节点,extends Component)-实现叶子节点的操作
4. 将叶子节点和节点组成最终的ALL节点。形成一棵树,而ALL节点就是树根。
5. 对树根进行操作,会将Leaf和Composite都当做Compoent一起处理。
3-实例代码
1-Component
public abstract class MenuComponent {
/*-------------------
* Composite methods
*-------------------*/
public void add(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public void remove(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public MenuComponent getChild(int i){
throw new UnsupportedOperationException();
}
/*-----------------------
* Operations by MenuItem
*-----------------------*/
public String getName() {
throw new UnsupportedOperationException();
}
public int getPrice() {
throw new UnsupportedOperationException();
}
//operation both Menu and MenuItem
public void print() {
throw new UnsupportedOperationException();
}
}
2-Composite
实现Menu的几个方法。
public class Menu extends MenuComponent{
ArrayList<MenuComponent> menuComponentList = new ArrayList<>();
String name;
public Menu(String name) {
this.name = name;
}
public void add(MenuComponent menuComponent) {
menuComponentList.add(menuComponent);
}
public void remove(MenuComponent menuComponent) {
menuComponentList.remove(menuComponent);
}
public MenuComponent getChild(int i) {
return menuComponentList.get(i);
}
public String getName() {
return name;
}
public void print() {
System.out.println("Menu Name:"+name);
System.out.println("--------------");
Iterator iterator = menuComponentList.iterator();
while(iterator.hasNext()) {
MenuComponent menuComponent = (MenuComponent) iterator.next();
menuComponent.print();
}
System.out.println("--------------");
}
}
3-Leaf
//实现MenuItem应该实现的方法
public class MenuItem extends MenuComponent{
String name;
int price;
public MenuItem(String name,int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public void print() {
System.out.println("name:"+name+" price:"+price);
}
}
4-对树根操作
public class Waitress {
MenuComponent allMenus;
public Waitress(MenuComponent allMenus) {
this.allMenus = allMenus;
}
public void printMenu() {
allMenus.print();
}
}
5-测试
public class Test {
public static void main(String[] args) {
MenuComponent pancakeMenu = new Menu("PancakeMenu");
MenuComponent dinerMenu = new Menu("DinerMenu");
MenuComponent cafeMenu = new Menu("CafeMenu");
MenuComponent dessertMenu = new Menu("DessertMenu");
MenuComponent allMenus = new Menu("all Menus");
allMenus.add(pancakeMenu);
allMenus.add(cafeMenu);
allMenus.add(dinerMenu);
pancakeMenu.add(new MenuItem("pancake1", 11));
pancakeMenu.add(new MenuItem("pancake2", 21));
pancakeMenu.add(new MenuItem("pancake3", 31));
dinerMenu.add(new MenuItem("diner1", 32));
dinerMenu.add(new MenuItem("diner2", 56));
dinerMenu.add(new MenuItem("diner3", 89));
dessertMenu.add(new MenuItem("dessert1", 23));
dessertMenu.add(new MenuItem("dessert2", 53));
dessertMenu.add(new MenuItem("dessert3", 92));
cafeMenu.add(new MenuItem("cafe1", 2));
cafeMenu.add(dessertMenu);
cafeMenu.add(new MenuItem("cafe2", 9));
Waitress waitress = new Waitress(allMenus);
waitress.printMenu();
}
}
4-组合和迭代器结合
给MenuCompoent增加createIterator()方法
public Iterator createIterator(){
throw new UnsupportedOperationException();
}
在Menu和MenuItem中实现
public Iterator createIterator() {
return new CompositeIterator(menuComponentList.iterator());
}
//Item没有迭代器
public Iterator createIterator() {
return new NullIterator();
}
实现迭代器
public class CompositeIterator implements Iterator{
Iterator iterator;
ArrayList<MenuComponent> componentList;
public CompositeIterator(Iterator iterator) {
this.iterator = iterator;
componentList = new ArrayList<>();
saveAll(iterator);
}
//将所有叶子节点加入链表
private void saveAll(Iterator iterator) {
while(iterator.hasNext()) {
MenuComponent menuComponent = (MenuComponent) iterator.next();
//componentList.add(menuComponent);
//菜单
if(menuComponent instanceof Menu) {
saveAll(menuComponent.createIterator());
}
else {
componentList.add(menuComponent); //将叶子加入
}
}
}
@Override
public boolean hasNext() {
return (componentList.size() == 0 ? false : true);
}
@Override
public Object next() {
MenuComponent component = componentList.get(0);
componentList.remove(0);
return component;
}
}
Waitress
public class Waitress {
MenuComponent allMenus;
public Waitress(MenuComponent allMenus) {
this.allMenus = allMenus;
}
public void printMenu() {
Iterator iterator = allMenus.createIterator();
while(iterator.hasNext()) {
MenuComponent menuComponent = (MenuComponent) iterator.next();
menuComponent.print();
}
}
}
测试代码不变,直接调用waitress的printMenu()即可
5-组合模式优点
能够让客户可以处理多个对象,而不需要知道对象实际的类型。
本文介绍了迭代器模式和组合模式的基本概念、结构及应用场景。迭代器模式提供了一种访问聚合对象的方式,无需暴露其内部表示;组合模式则用于处理整体/部分层次结构,使得客户端能一致地处理单一对象和对象组合。
661





