《设计模式入门》 17.迭代器模式

        迭代器模式就是提供一种方法,顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。也就是说可以让我们以相同的方式,遍历不同的数据结构元素,这些数据结构包括;数组链表等,而用户在使用遍历的时候并不需要去关心每一种数据结构的遍历处理逻辑,从让使用变得统一易用。

不同种类的对象可能需要不同的遍历方式,所以我们对每一种类型的对象配一个迭代器,最后把多个迭代器合成一个进行调用。

一般,迭代器模式分为四个角色:

  1. 迭代器角色(Iterator):定义遍历元素所需要的方法,一般来说会有这么三个方法:取得下一个元素的方法next(),判断是否遍历结束的方法hasNext()),移出当前对象的方法remove(),
  2. 具体迭代器角色(Concrete Iterator):实现迭代器接口中定义的方法,完成集合的迭代。
  3. 容器角色(Aggregate): 一般是一个接口,提供一个iterator()方法,例如java中的Collection接口,List接口,Set接口等
  4. 具体容器角色(ConcreteAggregate):就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等

 其实迭代器我们再java中也是熟面孔了,我们的arrayList中就有iterator:

定义迭代器:

public Iterator<E> iterator() {
    return new Itr();
}

分层迭代,遍历arrayList直到arrayList的最后一个,返回对应的值:

private class Itr implements Iterator<E> {
    
    /**
   		 cursor:表示下一个元素的索引位置
  		lastRet:表示上一个元素的索引位置
  		expectModCount:预期被修改的次数
    **/
    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;
	
    //判断是否存在下一个
    public boolean hasNext() {
        //当cursor不等于size时,表示仍有索引元素
        return cursor != size;
    }
	
    
    @SuppressWarnings("unchecked")
    //返回下一个元素
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            //判断集合的修改次数是否合法。
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void forEachRemaining(Consumer<? super E> consumer) {
        Objects.requireNonNull(consumer);
        final int size = ArrayList.this.size;
        int i = cursor;
        if (i >= size) {
            return;
        }
        final Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length) {
            throw new ConcurrentModificationException();
        }
        while (i != size && modCount == expectedModCount) {
            consumer.accept((E) elementData[i++]);
        }
        // update once at end of iteration to reduce heap write traffic
        cursor = i;
        lastRet = i - 1;
        checkForComodification();
    }

    final void checkForComodification() {
        //modCount用于记录集合被修改的次数
        //每当集合内部结构发生变化(add,remove,set)时,modCount+1。
        if (modCount != expectedModCount)
            //expectedModCount记录当前集合修改的次数,初始化为集合的modCount值
            throw new ConcurrentModificationException();
    }
}

我们可以仿照他来写一个:

=========================================================================

我们选择两个菜单,一个食物菜单用ArrayList来存

一个饮料菜单用HashMap来存

并且通过迭代器遍历输出菜单。

=========================================================================

迭代器角色:

package IteratorPattern;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName Iterator.java
 * @Description 迭代器
 * @createTime 2022年03月14日 14:52:00
 */
public interface Iterator<E> {
    /**
     * 是否存在下一个节点
     * @return 存在true,不存在false
     */
     boolean hasNext();

    /**
     * 下一个节点的值
     * @return 下一个节点
     */
     Object next();
}

可迭代接口:

package IteratorPattern;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName Iterable.java
 * @Description 可迭代接口
 * @createTime 2022年03月14日 14:54:00
 */
public interface Iterable<E> {
        /**
         * 迭代器
         * @return 迭代器
         */
        Iterator <E> iterator();
}

容器接口:

package IteratorPattern;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName Collection.java
 * @Description 集合功能接口定义
 * @createTime 2022年03月14日 15:02:00
 */
public interface Collection<E> extends Iterable<E> {
    /**
     * 增加节点
     * @param e 节点
     * @return 是否成功增加: true成功,false失败
     */
    boolean add(E e);
}

定义菜单中的原素:

package IteratorPattern;

import java.math.BigDecimal;
import java.util.ArrayList;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName Menu.java
 * @Description 菜单元素
 * @createTime 2022年03月14日 14:58:00
 */
public class MenuItem {
    private String name;
    private BigDecimal price;

    public MenuItem(String name, BigDecimal price){
        this.name=name;
        this.price=price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

我们用Map存储数据,需要得到两个原素之间的联系用于遍历:

package IteratorPattern;

import java.util.Objects;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName MenuLink.java
 * @Description 联系
 * @createTime 2022年03月14日 15:58:00
 */
public class MenuLink {
    private MenuItem firstMenu;
    private MenuItem secondMenu;

    public MenuLink(MenuItem menuItem1, MenuItem menuItem2) {
        this.firstMenu = menuItem1;
        this.secondMenu = menuItem2;
    }

    public MenuItem getFirstMenu() {
        return firstMenu;
    }

    public MenuItem getSecondMenu() {
        return secondMenu;
    }

    public void setFirstMenu(MenuItem firstMenu) {
        this.firstMenu = firstMenu;
    }

    public void setSecondMenu(MenuItem secondMenu) {
        this.secondMenu = secondMenu;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof MenuLink)) {
            return false;
        }
        MenuLink menuLink = (MenuLink) o;
        return Objects.equals(getFirstMenu(), menuLink.getFirstMenu()) && Objects.equals(getSecondMenu(), menuLink.getSecondMenu());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getFirstMenu(), getSecondMenu());
    }
}

我们通过实现容器接口,得到食物菜单和饮料菜单:

食物菜单(用ArrayList存):

package IteratorPattern;

import java.util.ArrayList;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName Menu.java
 * @Description 食物菜单
 * @createTime 2022年03月14日 15:00:00
 */
public class FoodMenu implements Collection<MenuItem>{
    private ArrayList<MenuItem> menu;

    public FoodMenu(ArrayList<MenuItem> menu) {
        this.menu = menu;
    }

    @Override
    public boolean add(MenuItem menuItem) {
        return menu.add(menuItem);
    }

    @Override
    public Iterator<MenuItem> iterator() {
        return new Iterator<MenuItem>() {
            private int location = 0;

            @Override
            public boolean hasNext() {
                return location<menu.size();
            }

            @Override
            public Object next() {
                MenuItem menuItem = menu.get(location);
                location++;
                return menuItem;
            }
        };
    }

}

饮料菜单(用MAP存):

package IteratorPattern;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName DrinkMenu.java
 * @Description 饮料菜单
 * @createTime 2022年03月14日 15:37:00
 */
public class DrinkMenu implements Collection<MenuItem>{
    private int index = 0;
    private Map<Integer,MenuLink> menuLinkMap;

    public DrinkMenu(Map<Integer,MenuLink> menuLinkMap){
        this.menuLinkMap = menuLinkMap;
    }


    @Override
    public boolean add(MenuItem menuItem) {
        if (menuLinkMap.isEmpty()){
            MenuLink menuLink = new MenuLink(menuItem,null);
            index++;
            return menuLinkMap.put(index,menuLink)!=null;
        }else {
            MenuLink menuLink = menuLinkMap.get(index);
            menuLink.setSecondMenu(menuItem);
            menuLinkMap.put(index,menuLink);
            MenuLink newMenuLink = new MenuLink(menuItem,null);
            index++;
            return menuLinkMap.put(index,newMenuLink)!=null;
        }
    }


    @Override
    public Iterator<MenuItem> iterator() {
        return new Iterator<MenuItem>() {
            private int location = 0;

            @Override
            public boolean hasNext() {
                return location<menuLinkMap.size();
            }

            @Override
            public Object next() {
                    location++;
                    MenuLink menuLink = menuLinkMap.get(location);
                    return menuLink.getFirstMenu();
            }
        };
    }
}

测试一下:

package IteratorPattern;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Zeyu Wan
 * @version 1.0.0
 * @ClassName IteratorTest.java
 * @Description 测试
 * @createTime 2022年03月14日 15:19:00
 */
public class IteratorTest {
    public static void main(String[] args) {
        ArrayList<MenuItem> menuList = new ArrayList<>();
        Collection<MenuItem> menu = new FoodMenu(menuList);
        menu.add(new MenuItem("炸鸡", BigDecimal.valueOf(20)));
        menu.add(new MenuItem("炸鸡翅", BigDecimal.valueOf(15)));
        menu.add(new MenuItem("炸香菇", BigDecimal.valueOf(9)));
        menu.add(new MenuItem("炸触手怪", BigDecimal.valueOf(12)));
        menu.add(new MenuItem("炸奶油", BigDecimal.valueOf(4)));

        Map<Integer,MenuLink> menuLinkMap = new HashMap<>();
        Collection<MenuItem> menu1 = new DrinkMenu(menuLinkMap);
        menu1.add(new MenuItem("矿泉水",BigDecimal.valueOf(1)));
        menu1.add(new MenuItem("可乐",BigDecimal.valueOf(2)));
        menu1.add(new MenuItem("鲜橙多",BigDecimal.valueOf(3)));
        menu1.add(new MenuItem("自来水",BigDecimal.valueOf(0)));


        System.out.println("==========食物菜单===========");
        printList(menu);
        System.out.println("==========饮料菜单===========");
        printList(menu1);
    }

    /**
     * 打印菜单方法
     * @param collection 传入的菜单
     */
    public static void printList(Collection<MenuItem> collection){
        Iterator<MenuItem> iterator = collection.iterator();

        while (iterator.hasNext()){
            MenuItem item2 = (MenuItem)iterator.next();
            System.out.println(item2.getName()+"========"+item2.getPrice());
        }
    }
}

可以看到,我们虽然通过不同的存储方式,但是都是通过迭代器进行迭代访问。

 

优点:

  1. 它支持以不同的方式遍历一个聚合对象。
  2. 迭代器简化了聚合类。
  3. 在同一个聚合上可以有多个遍历。
  4. 在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。

缺点:

  1. 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 《图解23种设计模式pdf》是一本以图解方式呈现的设计模式学习资料。本书通过图文并茂的方式,详细介绍了23种常用的设计模式,对于初学者来说非常友好。 设计模式是软件开发领域中常用的设计思想和经验总结。通过学习设计模式,可以帮助我们更好地理解和应用面向对象设计的原则和理念。而这本《图解23种设计模式pdf》通过图解的形式,将抽象的设计概念用简单易懂的方式呈现出来,让初学者更容易理解和学习。 这本书从创建型、结构型和行为型三个方面介绍了各种设计模式。创建型设计模式包括单例模式、工厂模式、建造者模式等,用于对象的创建和初始化;结构型设计模式包括适配器模式、装饰器模式、代理模式等,用于对象的组合和组织;行为型设计模式包括观察者模式、策略模式迭代器模式等,用于对象之间的相互作用。 每一种设计模式都有详细的图解和示例代码。通过学习这些图解和代码示例,我们可以更好地理解每个设计模式的应用场景和实现方式。同时,这本书也给出了每个设计模式的优缺点和适用情况,帮助读者更好地选择和应用设计模式。 总之,《图解23种设计模式pdf》是一本非常实用的设计模式学习资料。无论是对于初学者还是有经验的开发者来说,这本书都能够帮助我们更好地理解和应用设计模式,提高软件开发的质量和效率。 ### 回答2: 《图解23种设计模式PDF》是一本简洁清晰的设计模式入门指南。这本书通过图解的方式,详细介绍了23种常见的设计模式,让读者能够更加直观地理解和使用这些模式。 首先,这本书对设计模式进行了系统的分类和组织,可以帮助读者更好地理解各种模式之间的关系。书中将设计模式分为三大类:创建型模式、结构型模式和行为型模式。每种模式都有一个独特的图解和相应的示例代码,使读者能够更容易地理解这些模式的原理和应用场景。 其次,这本书特别注重实际应用。每个设计模式都有对应的实际案例,并且通过示例代码对其进行了详细解释。通过这些案例,读者可以了解如何使用设计模式解决真实世界中的问题,并学会将其应用于自己的项目中。 此外,这本书还提供了一些设计模式的最佳实践和注意事项。这些内容对于读者在使用设计模式时具有指导作用,并能帮助读者避免一些常见的错误。 总之,《图解23种设计模式PDF》是一本适合初学者的设计模式入门指南。通过图解和实例,读者可以快速掌握各种设计模式的原理和应用,并学会将其灵活运用于自己的项目中。无论是想了解设计模式的基本概念,还是想提高自己的设计能力,这本书都是一个很好的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

PigeonEssence

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

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

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

打赏作者

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

抵扣说明:

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

余额充值