迭代器模式和组合模式-《Head First 设计模式》

来源:互联网 发布:手机apk反编译软件 编辑:程序博客网 时间:2024/05/21 10:52

问题汇总

  1. 迭代器定义和作用
    迭代器遍历一个聚合物,并将其封装成另一个对象。
  2. 迭代器适用场景
  3. 迭代器模式的结构和实现方法
  4. 组合模式定义和作用以及适用场景
    适用于“整体/部分”的关系结构,用于统一处理所有对象(不分节点还是叶子)。
  5. 组合模式结构和实现的两种方案。
    • 树结构。
    • 将所有功能都加入到Component中。或者将不同功能通过接口来赋予不同对象。其间的思想就是透明度和安全性的平衡。
  6. 迭代器设计原则:一个类一个功能。
  7. 观察者和状态模式的区别
    • 观察者:当状态改变时,通知一组对象。
    • 状态:当状态改变时,让一个对象改变行为。

问题答案日后补充

  • 问题汇总
  • 1-迭代器模式
    • 1-定义
    • 2-结构
      • 使用
    • 3-设计原则
    • 4-Java5遍历集合而不用显式Iterator
    • 5-实例餐厅
      • 1-MenuItem
      • 2-Menu
      • 3-Iterator
      • 4-服务员和测试
  • 2-组合模式Composite Pattern
    • 1-定义
    • 2-结构
    • 3-实例代码
      • 1-Component
      • 2-Composite
      • 3-Leaf
      • 4-对树根操作
      • 5-测试
    • 4-组合和迭代器结合
    • 5-组合模式优点

1-迭代器模式

1-定义:

提供一种方法能够顺序访问聚合对象中的元素,而不需要暴露内部的表示。

2-结构:

  1. 聚合接口(Aggregate)-提供createIterator方法
  2. ConcreteAggregate-实现聚合接口中的createIterator方法
  3. Iterator(迭代器接口)-提供hasNext\next等方法
  4. 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-组合模式优点

能够让客户可以处理多个对象,而不需要知道对象实际的类型。