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

问题汇总

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

问题答案日后补充

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-组合模式优点

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

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值