《HeadFirst设计模式(第二版)》第九章代码——迭代器模式

这篇具有很好参考价值的文章主要介绍了《HeadFirst设计模式(第二版)》第九章代码——迭代器模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

情景:

        一家早餐店和一家午餐点准备合并在一起,两家的点菜的菜单实现方式如下:

        首先,他们的菜单选项都基于同一个类:

菜单选项类
package Chapter9_IteratorPattern.Origin;

/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public class MenuItem {
    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 boolean isVegetarian() {
        return vegetarian;
    }

    public double getPrice() {
        return price;
    }
}
早餐店初始菜单
package Chapter9_IteratorPattern.Origin;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public class PancakeHouseMenu {
    List<MenuItem> menuItems;

    public PancakeHouseMenu(){
        this.menuItems = new ArrayList<MenuItem>();
        addItem("K&B's Pancake Breakfast",
                "Pancake with scrambled eggs and toast",
                true,
                2.99);
        addItem("Regular Pancake Breakfast",
                "Pancake with fired eggs, sausage",
                false,
                2.99);
        addItem("BlueBerry Pancake",
                "Pancake made with fresh blueberries",
                true,
                3.49);
        addItem("Waffles",
                "Waffles with your choice of blueberries of strawberries",
                true,
                3.59);
    }

    public void addItem(String name,String description,
                        boolean vegetarian,double price){
        MenuItem menuItem = new MenuItem(name,description,vegetarian,price);
        this.menuItems.add(menuItem);
    }

    public List<MenuItem> getMenuItems(){
        return this.menuItems;
    }
}
午餐店初始菜单:
package Chapter9_IteratorPattern.Origin;

/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public class DinerMenu {
    static final int MAX_ITEMS = 6;
    int numberOfItems = 0;
    MenuItem[] menuItems;

    public DinerMenu(){
        this.menuItems = new MenuItem[MAX_ITEMS];
        addItem("aaa","food1",true,2.99);
        addItem("bbb","food2",true,2.99);
        addItem("ccc","food3",true,3.29);
        addItem("ddd","food4",true,3.05);
    }

    public void addItem(String name,String description,
                        boolean vegetarian,double price){
        MenuItem menuItem = new MenuItem(name,description,vegetarian,price);
        if(this.numberOfItems >= MAX_ITEMS){
            System.out.println("Sorry! Menu is full!");
        }else{
            this.menuItems[this.numberOfItems] = menuItem;
            this.numberOfItems++;
        }
    }

    public MenuItem[] getMenuItems(){
        return this.menuItems;
    }
}

可以得知:前者使用List来实现,后者使用数组来实现。

这时候,如果不采取任何方法加以更改,新餐厅的服务员将要这样使用两个菜单:

服务员类初始
package Chapter9_IteratorPattern.Origin;

import java.util.List;

/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public class Waitress {
    public void printMenu(){
        //遍历菜单
        PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
        List<MenuItem> breakfastItems = pancakeHouseMenu.getMenuItems();

        DinerMenu dinerMenu = new DinerMenu();
        MenuItem[] lunchItems = dinerMenu.getMenuItems();

        for(int i= 0;i<breakfastItems.size();++i){
            MenuItem menuItem = breakfastItems.get(i);
            System.out.println(menuItem.getName()+"  ");
            System.out.println(menuItem.getPrice()+"  ");
            System.out.println(menuItem.getDescription()+"  ");
        }

        for(int i = 0;i<lunchItems.length;++i){
            MenuItem menuItem = lunchItems[i];
            System.out.println(menuItem.getName()+"  ");
            System.out.println(menuItem.getPrice()+"  ");
            System.out.println(menuItem.getDescription()+"  ");
        }
    }

    public static void main(String[] args) {
        Waitress waitress = new Waitress();
        waitress.printMenu();
    }
}

由此可见:服务员类和两个菜单类直接接触,既违反封装原理,还违背了面向接口编码的原理,同时极其不利于维护。

迭代器模式

这时可以采用迭代器模式:在两个菜单和服务员之间加入一个迭代器(iterator),迭代器负责直接处理菜单的遍历等功能,然后服务员通过这个迭代器来使用菜单,成功解耦。

简介

        迭代器提供一种方式,可以访问一个聚合对象中的元素而又不暴露其潜在实现。

        同时把遍历的任务放到迭代器上而不是聚合上,这就简化了聚合的接口和实现(让聚合只需负责管理对象集合即可),满足单一责任原则。

自定义的迭代器

自定义迭代器接口
package Chapter9_IteratorPattern.MyIterator;

/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public interface Iterator {

    //提供一个统一的迭代器接口,在用户和对象集合之间加入迭代器,
    //迭代器中含有遍历集合的具体操作,不需要关心如何实现
    boolean hasNext();
    MenuItem next();
}
早餐迭代器:
package Chapter9_IteratorPattern.MyIterator;

import java.util.List;

/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public class PancakeHouseIterator implements Iterator{
    List<MenuItem> items;
    int position = 0;

    public PancakeHouseIterator(List<MenuItem> items){
        this.items = items;
    }

    @Override
    public MenuItem next() {
        MenuItem menuItem = items.get(position);
        position++;
        return menuItem;
    }

    @Override
    public boolean hasNext() {
        if(position >= items.size() || items.get(position) == null){
            return false;
        }else{
            return true;
        }
    }
}
使用迭代器的早餐菜单

加入一个新方法即可:

    public Iterator createIterator(){
        return new PancakeHouseIterator(menuItems);
    }
午餐迭代器:
package Chapter9_IteratorPattern.MyIterator;

/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public class DinerMenuIterator implements Iterator{
    MenuItem[] items;
    int position = 0;

    public DinerMenuIterator(MenuItem[] items){
        this.items = items;
    }

    @Override
    public MenuItem next() {
        MenuItem menuItem = items[position];
        position++;
        return menuItem;
    }

    @Override
    public boolean hasNext() {
        if(position >= items.length || items[position] == null){
            return false;
        }else{
            return true;
        }
    }
}
使用迭代器的午餐菜单:

同理:

    public Iterator createIterator(){
        //提供一个接口使得迭代器获取到该集合
        return new DinerMenuIterator(menuItems);
    }

使用自定义迭代器的服务员类:

package Chapter9_IteratorPattern.MyIterator;

/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public class Waitress {
    PancakeHouseMenu pancakeHouseMenu;
    DinerMenu dinerMenu;

    public Waitress(PancakeHouseMenu pancakeHouseMenu,
                    DinerMenu dinerMenu){
        this.pancakeHouseMenu = pancakeHouseMenu;
        this.dinerMenu = dinerMenu;
    }

    public void printMenu(){
        Iterator pancakeMenuIterator = pancakeHouseMenu.createIterator();
        Iterator dinerIterator = dinerMenu.createIterator();

        System.out.println("MENU\n----\nBREAKFAST");
        printMenu(pancakeMenuIterator);
        System.out.println("\nLUNCH");
        printMenu(dinerIterator);

    }

    private void printMenu(Iterator iterator){
        while(iterator.hasNext()){
            MenuItem menuItem = iterator.next();
            System.out.println(menuItem.getName()+"  ");
            System.out.println(menuItem.getPrice()+"  ");
            System.out.println(menuItem.getDescription()+"  ");
        }
    }
}
测试类:
package Chapter9_IteratorPattern.MyIterator;

/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public class MenuTestDrive {
    public static void main(String[] args) {
        PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
        DinerMenu dinerMenu = new DinerMenu();

        Waitress waitress = new Waitress(pancakeHouseMenu,dinerMenu);
        waitress.printMenu();
    }
}

使用JAVA自带的迭代器

因为早餐菜单使用了ArrayList,它有iterator()方法返回一个迭代器(所以这里可以删除掉它的自定义迭代器),然而午餐菜单是用数组实现的,没有这个方法,所以午餐类还是需要使用自定义的迭代器(“继承”于java的迭代器)。

修改早餐类:

添加头文件:

import java.util.Iterator;

然后修改方法:

    public Iterator<MenuItem> createIterator(){
        return menuItems.iterator();
    }
修改午餐迭代器类:
package Chapter9_IteratorPattern.JavaIterator;
import java.util.Iterator;

/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public class DinerMenuIterator implements Iterator<MenuItem>{
    MenuItem[] items;
    int position = 0;

    public DinerMenuIterator(MenuItem[] items){
        this.items = items;
    }

    @Override
    public MenuItem next() {
        MenuItem menuItem = items[position];
        position++;
        return menuItem;
    }

    @Override
    public boolean hasNext() {
        if(position >= items.length || items[position] == null){
            return false;
        }else{
            return true;
        }
    }

    @Override
    public void remove() {
        //java自带的迭代器是由remove()方法的,所以这里必须要实现
        throw new UnsupportedOperationException("you can not remove it!");
    }
}
添加Menu接口:
package Chapter9_IteratorPattern.JavaIterator;

import java.util.Iterator;

/**
 * @Author 竹心
 * @Date 2023/8/18
 **/

public interface Menu {
    public Iterator<?> createIterator();
}

记得分别在午餐菜单类和早餐菜单类的类声明那里加上对Menu的实现:

public class DinerMenu implements Menu{...}

public class PancakeHouseMenu implements Menu{...}
修改服务员类:
package Chapter9_IteratorPattern.JavaIterator;
import java.util.Iterator;
/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public class Waitress {
    Menu pancakeHouseMenu;
    Menu dinerMenu;

    public Waitress(Menu pancakeHouseMenu,Menu dinerMenu){
        this.pancakeHouseMenu = pancakeHouseMenu;
        this.dinerMenu = dinerMenu;
    }

    public void printMenu(){
        Iterator<?> pancakeMenuIterator = pancakeHouseMenu.createIterator();
        Iterator<?> dinerIterator = dinerMenu.createIterator();

        System.out.println("MENU\n----\nBREAKFAST");
        printMenu(pancakeMenuIterator);
        System.out.println("\nLUNCH");
        printMenu(dinerIterator);

    }

    private void printMenu(Iterator iterator){
        while(iterator.hasNext()){
            MenuItem menuItem = (MenuItem) iterator.next();
            System.out.println(menuItem.getName()+"  ");
            System.out.println(menuItem.getPrice()+"  ");
            System.out.println(menuItem.getDescription()+"  ");
        }
    }
}

情景扩展1

        好了,现在又有一家咖啡店并入餐厅,并在晚上提供服务,这家咖啡店也有它独特的菜单实现方式:使用哈希表!接下来要将它加入迭代器的使用中(这里将其称为晚餐菜单):

使用JAVA自带迭代器的晚餐菜单:
package Chapter9_IteratorPattern.AddCafe;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @Author 竹心
 * @Date 2023/8/18
 **/

public class CafeMenu implements Menu{
    HashMap<String, MenuItem> menuItems = new HashMap<String, MenuItem>();

    public CafeMenu() {
        addItem("Veggie Burger and Air Fries",
                "Veggie burger on a whole wheat bun, lettuce, tomato, and fries",
                true, 3.99);
        addItem("Soup of the day",
                "A cup of the soup of the day, with a side salad",
                false, 3.69);
        addItem("Burrito",
                "A large burrito, with whole pinto beans, salsa, guacamole",
                true, 4.29);
    }

    public void addItem(String name, String description,
                        boolean vegetarian, double price)
    {
        MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
        menuItems.put(name, menuItem);
    }

//    public Map<String, MenuItem> getItems() {
//        return menuItems;
//    }

    public Iterator<MenuItem> createIterator() {
        //获取哈希表中的集合的迭代器
        return menuItems.values().iterator();
    }
}
修改后的服务员类:
package Chapter9_IteratorPattern.AddCafe;

import java.util.Iterator;
/**
 * @Author 竹心
 * @Date 2023/8/17
 **/

public class Waitress {
    Menu pancakeHouseMenu;
    Menu dinerMenu;
    Menu cafeMenu;

    public Waitress(Menu pancakeHouseMenu, Menu dinerMenu, Menu cafeMenu){
        this.pancakeHouseMenu = pancakeHouseMenu;
        this.dinerMenu = dinerMenu;
        this.cafeMenu = cafeMenu;
    }

    public void printMenu(){
        Iterator<?> pancakeMenuIterator = pancakeHouseMenu.createIterator();
        Iterator<?> dinerIterator = dinerMenu.createIterator();
        Iterator<?> cafeIterator = cafeMenu.createIterator();

        System.out.println("MENU\n----\nBREAKFAST");
        printMenu(pancakeMenuIterator);
        System.out.println("\nLUNCH");
        printMenu(dinerIterator);
        System.out.println("\nDINNER");
        printMenu(cafeIterator);

    }

    private void printMenu(Iterator iterator){
        while(iterator.hasNext()){
            MenuItem menuItem = (MenuItem) iterator.next();
            System.out.println(menuItem.getName()+"  ");
            System.out.println(menuItem.getPrice()+"  ");
            System.out.println(menuItem.getDescription()+"  ");
        }
    }
}

        现在,我们发现,如果菜单越来越多,服务员类涉及到的操作也越来越多,所以这里可以对服务员类进行优化:

优化后的服务员类
package headfirst.designpatterns.iterator.transition;
import java.util.*;
  

/**
 * @Author 竹心
 * @Date 2023/8/18
 **/


public class Waitress {
	ArrayList<Menu> menus;
     
  
	public Waitress(ArrayList<Menu> menus) {
		this.menus = menus;
	}
   
	public void printMenu() {
		Iterator<?> menuIterator = menus.iterator();
		while(menuIterator.hasNext()) {
			Menu menu = (Menu)menuIterator.next();
			printMenu(menu.createIterator());
		}
	}
   
	void printMenu(Iterator<?> iterator) {
		while (iterator.hasNext()) {
			MenuItem menuItem = (MenuItem)iterator.next();
			System.out.print(menuItem.getName() + ", ");
			System.out.print(menuItem.getPrice() + " -- ");
			System.out.println(menuItem.getDescription());
		}
	}
}  

情景扩展2

        现在问题来了,如果菜单中存在子菜单,那么又该如何实现呢?

        很明显上面的方法已经不适用了,重写菜单代码才行。

        这里就引出了组合模式:

《HeadFirst设计模式(第二版)》第九章代码——组合模式_轩下小酌的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-662662.html

到了这里,关于《HeadFirst设计模式(第二版)》第九章代码——迭代器模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 《HeadFirst设计模式(第二版)》第十一章代码——代理模式

    代码文件目录:  RMI: MyRemote MyRemoteClient MyRemoteImpl 能够远程监控的糖果机: 在上一章的代码的基础上做一些修改 GumballMachine GumballMachineRemote GumballMachineTestDrive GumballMonitor GumballMonitorTestDrive 五个状态类: 同样的修改:

    2024年02月12日
    浏览(38)
  • 《HeadFirst设计模式(第二版)》第八章代码——模板方法模式

    代码文件目录:   CaffeineBeverage Coffee Tea notes

    2024年02月12日
    浏览(40)
  • 《HeadFirst设计模式(第二版)》第五章代码——单例模式

    代码文件目录:  初始版本: 三种解决多线程问题的方法: Notes:

    2024年02月13日
    浏览(39)
  • JAVA设计模式第九章:建造者模式

    通过将对象的构建过程从表现层隔离出来,使得相同的构建过程可以用来创建不同的表现形式 用于简化和优化复杂对象的创建过程,提高创建效率和代码可读性; Product(产品角色): 要创建的产品对象 Builder(抽象建造者): 创建产品以及部件的接口定义 ConcreateBuilder(具体建造者): 抽

    2024年02月19日
    浏览(38)
  • 设计模式第九讲:常见重构技巧 - 去除不必要的!=

    项目中会存在大量判空代码,多么丑陋繁冗!如何避免这种情况?我们是否滥用了判空呢?本文是设计模式第九讲,讲解常见重构技巧:去除不必要的!= 通常是这样的 初步的,使用Apache Commons,Guvava,Hutool等 StringUtils 考虑用Assert断言 逐级判断空,还是抛出自定义异常,还是

    2024年02月11日
    浏览(42)
  • 【Java基础教程】(十五)面向对象篇 · 第九讲:抽象类和接口——定义、限制与应用的细节,初窥模板设计模式、工厂设计模式与代理设计模式~

    掌握 抽象类和接口的定义、使用、区别、常见设计模式; 抽象类是代码开发中的重要组成部分,利用抽象类可以明确地定义子类需要覆写的方法,这样相当于在语法程度上对子类进行了严格的定义限制,代码的开发也就更加标准。下面具体介绍抽象类的概念。 普通类可以直

    2024年02月16日
    浏览(48)
  • 《微服务架构设计模式》第二章

    软件架构的定义 看一下大佬是怎么说的: 计算机系统的软件架构是构建这个系统所需要的一组结构,包括软件元素、它们之间的关系以及两者的属性。 --Bass等著《Documenting Software Architectures:Views and Beyond》 这个定义将软件分解为元素和元素之间的关系两个部分,就像一辆汽车

    2024年02月09日
    浏览(43)
  • 二十三种设计模式第二十篇--备忘录模式

    备忘录模式,备忘录模式属于行为型模式。它允许在不破坏封装的情况下捕获和恢复对象的内部状态。 保存一个对象的某个状态,以便在适当的时候恢复对象,该模式通过创建一个备忘录对象来保存原始对象的状态,并将其存储在一个负责管理备忘录的负责人对象中。 备忘

    2024年02月14日
    浏览(42)
  • 二十三种设计模式第二十四篇--访问者模式(完结撒花)

    在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。 通过这种方式,元素的执行算法可以随着访问者改变而改变。 这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的

    2024年02月14日
    浏览(44)
  • 《微服务架构设计模式》第二章 服务的拆分策略

    内容总结自《微服务架构设计模式》 软件架构的定义:计算机系统的软件架构是构建这个系统所需要的一组结构,包括软件元素、他们之间的关系以及两者的属性(Bass等著) 其实质是应用程续的架构将软件分解为元素(element)和这些元素之间的关系(relation)。由于这两个

    2024年02月09日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包