headFirst学习笔记之九:迭代器与组合模式(5.1)

作者:网络    软件教程库   2020-05-15

1.任务:

大新闻!对象村餐厅和对象村煎饼屋合并了!可以在同一个地方吃早饭和午饭了hohoho(有什么好开森的对象村的小伙伴们好容易满足)。

但是有一个问题出现了:煎饼屋的菜单menu是用arraylist记录菜单项menuitem,但是餐厅的菜单menu使用数组array记录menuitem。大家都不愿意修改自己的结构,那么java女招待的任务就很繁重了啊,因为取出菜单项的方法就要记住两种了:menuitems.get(i)和menuitems[i]

 1 public class menuitem {
 2     string name;
 3     string description;
 4     boolean vagetarian;
 5     double price;
 6     public menuitem(string name, string description, boolean vagetarian,
 7             double price) {
 8         super();
 9         this.name = name;
10         this.description = description;
11         this.vagetarian = vagetarian;
12         this.price = price;
13     }
14     public string getname() {
15         return name;
16     }
17     public string getdescription() {
18         return description;
19     }
20     public boolean isvagetarian() {
21         return vagetarian;
22     }
23     public double getprice() {
24         return price;
25     }
26 }

 1 public class pancakehousemenu {
 2     arraylist menuitems;
 3     
 4     public pancakehousemenu(){
 5         menuitems = new arraylist();
 6         
 7         additem("liyuhui‘s pancake breakfast","with eggs and toast",true,2.99);
 8         additem("zhangwuan‘s pancake breakfast","with onion",true,3.99);
 9         additem("jiangwen‘s pancake breakfast","with beaf",false,5.99);
10     }
11 
12     private void additem(string name, string description, boolean vegetarian, double price) {
13         menuitem menuitem = new menuitem(name, description, vegetarian, price);
14         menuitems.add(menuitem);
15     }
16     
17     public arraylist getmenuitems(){
18         return menuitems;
19     }
20 }

 1 public class dinermenu {
 2     static final int max_items = 6;
 3     int numberofitems = 0;
 4     menuitem[] menuitems;
 5     
 6     public dinermenu(){
 7         menuitems = new menuitem[max_items];
 8         
 9         additem("liyuhui‘s lunch","with eggs",true,6.99);
10         additem("zhangwuan‘s lunch","with potatoes",true,6.99);
11         additem("jiangwen‘s lunch","with beaf",false,5.99);
12     }
13 
14     private void additem(string name, string description, boolean vegetarian, double price) {
15         menuitem menuitem = new menuitem(name, description, vegetarian, price);
16         if(numberofitems = max_items){
17             system.out.println("menu is full");
18         }else{
19             menuitems[numberofitems] = menuitem;
20             numberofitems++;
21         }
22     }
23     
24     public menuitem[] getmenuitems(){
25         return menuitems;
26     }
27 }

 1 public class waitress {
 2     pancakehousemenu ohmenu = new pancakehousemenu();
 3     arraylist breakfirst = ohmenu.getmenuitems();
 4     
 5     dinermenu dmenu = new dinermenu();
 6     menuitem[] lunch = dmenu.getmenuitems();
 7     
 8     public void printmenu(){
 9         for(int i=0;ibreakfirst.size();i++){
10             menuitem menuitem = (menuitem) breakfirst.get(i);
11             system.out.println(menuitem.getname());
12             system.out.println(menuitem.getprice());
13             system.out.println(menuitem.getdescription());
14         }
15         
16         for(int i=0;ilunch.length;i++){
17             menuitem menuitem = (menuitem) lunch[i];
18             system.out.println(menuitem.getname());
19             system.out.println(menuitem.getprice());
20             system.out.println(menuitem.getdescription());
21         }
22     }
23 }

那么问题来了:java女招待的任务是打印出所有的菜单项,显然需要两个for循环,因为元素类型不一样。(1)重复代码太多,显然不是好事情。(2)如果要加一份菜单,就需要再加一个循环,waitress这个类就需要无休止的change维护。

2.如何解决大部分重复的for循环问题:

思路:原则永远是封装变化的部分。这里变化的就是for循环,不同的集合类型,会造成遍历中的部分差别。那么我们就需要封装这个遍历,即使用迭代器模式~迭代器模式提供一种方法,顺序访问collection对象中的每一个元素,而又不暴露其内部的表示。

1 for(int i=0;ibreakfirst.size();i++){
2         menuitem menuitem = (menuitem) breakfirst.get(i);
3 }
4 
5 for(int i=0;ilunch.length;i++){
6         menuitem menuitem = (menuitem) lunch[i];
7 }

1 iterator iterator = (某一个menu).createiterator();
2 while(iterator.hasnext()){
3   menuitem menuitem = (menuitem)iterator.next();
4 }

3.迭代器模式下的修改:

发生的变化:

(1)以前需要两个for循环来遍历,现在有了迭代器,可以多态的处理任何项的集合。

(2)waitress类以前依赖于具体类menuitem[]和arraylist,现在只使用一个接口iterator(也就是说,不管以后item是以数组、list还是hashtable存储,都不用修改waitress的代码,这就是解耦)。

(3)waitress类依赖于具体类pancakehousemenu和dinermenu类,现在还是如此(结构体那里需要传入,如果修改了类,比如是另外两种菜单类型,waitress类需要修改,所以还没解耦),待改进。

 1 public interface iterator {
 2     boolean hasnext();
 3     object next();
 4 }
 5 
 6 public class dinermenuiterator implements iterator {
 7     menuitem[] items;
 8     int position = 0;
 9     
10     public dinermenuiterator(menuitem[] items) {
11         super();
12         this.items = items;
13     }
14 
15     public boolean hasnext() {
16         if(items[position] == null || position = items.length){
17             return false;
18         }else{
19             return true;
20         }
21     }
22 
23     public object next() {
24         menuitem menuitem = items[position];
25         position++;
26         return menuitem;
27     }
28 }

 1 public class dinermenu {
 2     ...
 3 //  public menuitem[] getmenuitems(){
 4 //      return menuitems;
 5 //  }
 6     
 7     public iterator creatiterator(){
 8         return new dinermenuiterator(menuitems);
 9     }
10 }

 1 public class waitress {
 2     pancakehousemenu phmenu = new pancakehousemenu();
 3     //arraylist breakfirst = ohmenu.getmenuitems();
 4     
 5     dinermenu dmenu = new dinermenu();
 6     //menuitem[] lunch = dmenu.getmenuitems();
 7     
 8     public waitress(pancakehousemenu phmenu, dinermenu dmenu) {
 9         super();
10         this.phmenu = phmenu;
11         this.dmenu = dmenu;
12     }
13     
14     public void printmenu(){
15 //        for(int i=0;ibreakfirst.size();i++){
16 //            menuitem menuitem = (menuitem) breakfirst.get(i);
17 //            system.out.println(menuitem.getname());
18 //            system.out.println(menuitem.getprice());
19 //            system.out.println(menuitem.getdescription());
20 //        }
21 //        
22 //        for(int i=0;ilunch.length;i++){
23 //            menuitem menuitem = (menuitem) lunch[i];
24 //            system.out.println(menuitem.getname());
25 //            system.out.println(menuitem.getprice());
26 //            system.out.println(menuitem.getdescription());
27 //        }
28         
29         iterator pancakeiterator = phmenu.createiterator();
30         iterator dineriterator = dmenu.creatiterator();
31         printmenuitems(pancakeiterator);
32         printmenuitems(dineriterator);
33     }
34 
35     private void printmenuitems(iterator iterator) {
36         while(iterator.hasnext()){
37             menuitem menuitem = (menuitem) iterator.next();
38             system.out.println(menuitem.getname());
39             system.out.println(menuitem.getprice());
40             system.out.println(menuitem.getdescription());
41         }    
42     }
43 }

 1 public class menutestdrive {
 2     public static void main(string[] args){
 3         pancakehousemenu phmenu = new pancakehousemenu();
 4         dinermenu dmenu = new dinermenu();
 5         
 6         waitress waitress = new waitress(phmenu,dmenu);
 7         waitress.printmenu();
 8        
 9     }
10 }

4.使用java的iterator接口:

前面从头到尾都是自己在创建iterator接口,然后实现具体类。但是实际上很多类在java里已经实现了iterator接口,比如arraylist,但是数组没有(所以还是要自己实现,但是不能使用刚刚的dinermenuiterator,因为两个menu的iterator要实现同一个接口!!!!)

1 import java.util.iterator;
2 public class pancakehousemenu {
3     ...
4     public iterator createiterator(){
5         //return new pancakemenuiterator(menuitems);
6         return menuitems.iterator();
7     }
8 }

 1 import java.util.iterator;
 2 public class dinermenuiterator implements iterator {
 3         ...
 4     public void remove() {
 5         if(position=0){
 6             throw new illegalstateexception
 7             ("you can‘t remove an item until you‘ve done at least one next()");
 8         }
 9         if(items[position-1]!=null){
10             //数组删除元素,要将后面的全体前移一个单位
11             for(int i=position-1;iitems.length-1;i++){
12                 items[i] = items[i+1];
13             }
14             items[items.length-1]=null;
15         }
16     }
17 }

5.改进3中的(3)问题:waitress还依赖于两个具体的菜单类pancakehousemenu和dinermenu。增加接口menu,waitress中全部只出现menu,所以实现了针对接口编程。

1 import java.util.iterator;
2 public interface menu {
3     public iterator createiterator();
4 }
5 
6 public class pancakemenu implements menu{}
7 
8 public class dinermenu implements menu{}

 1 import java.util.iterator;
 2 public class waitress {
 3     menu phmenu = new pancakehousemenu();
 4     menu dmenu = new dinermenu();
 5     
 6     public waitress(menu phmenu, menu dmenu) {
 7         super();
 8         this.phmenu = phmenu;
 9         this.dmenu = dmenu;
10     }
11     ...
12 }

 1 public class menutestdrive {
 2     public static void main(string[] args){
 3         menu phmenu = new pancakehousemenu();
 4         menu dmenu = new dinermenu();
 5         
 6         waitress waitress = new waitress(phmenu,dmenu);
 7         waitress.printmenu();
 8        
 9     }
10 }

6.现在咖啡厅也要作为合伙人啦 ,这样对象村的小伙伴们可以在同一个地方喝咖啡,吃早饭然后吃午饭了!(这样真的好吗~-_-)而咖啡厅一向逼格比较高,它的菜单项item是用hashtable存储的,该怎么做?

原码如下:

 1 public class cafemenu{
 2     hashtable menuitems = new hashtable();
 3     
 4     public cafemenu(){
 5         additem("liyuhui‘s cafe","with sugar",true,6.99);
 6         additem("zhangwuan‘s cafe","with milk",true,6.99);
 7         additem("jiangwen‘s cafe","with nothing",false,5.99);
 8     }
 9     
10     private void additem(string name, string description, boolean vegetarian, double price) {
11         menuitem menuitem = new menuitem(name, description, vegetarian, price);
12         menuitems.put(menuitem.getname(), menuitem);
13     }
14 
15     public hashtable getitems(){
16         return menuitems;
17     }
18 }

(2)修改后:(注意hashtable是menuitems.values().iterator()

 1 public class cafemenu implements menu {
 2         ...
 3 //  public hashtable getitems(){
 4 //      return menuitems;
 5 //  }
 6     
 7     public iterator createiterator() {
 8         // todo auto-generated method stub
 9         return menuitems.values().iterator();
10     }
11 }

(3)waitress的结构体增加一个menu cafemenu即可。

那么问题来了:增加一份菜单,就要将waitress的结构体修改下,并且测试程序也要修改,要调用print三次,显然也不是件很妙的事情。

解决办法:将菜单也打包遍历。

 1 public class waitress {
 2     arraylist menus;
 3     
 4     public waitress(arraylist menus) {
 5         super();
 6         this.menus = menus;
 7     }
 8 
 9     public void printmenu(){
11         iterator menuiterator = menus.iterator();
12         while(menuiterator.hasnext()){
13             menu menu = (menu) menuiterator.next();
14             printmenuitems(menu.createiterator());
15         }
16     }
17     ...
18 }

7.三合一吃饭地又要增加新功能了,希望能够加上一份餐后甜点的子菜单,即dinermenu中有一项是餐后甜点,这一项里面又有很多菜单项,比如说臭豆腐,辣条和广东蛋筒(嗯~我会选广东蛋筒)。

明确任务:之前的结构已经不足以支持这个功能了。那么我们需要什么呢?(我们需要组合模式!!!)

(1)需要某种树形结构,可以容纳菜单,子菜单,子子菜单...然后菜单项。

(2)我们要能够在每个菜单的各个item中游走遍历,也能够选择是遍历所有item还是只遍历某一个菜单的item。

解决办法:创建一个组件接口component作为菜单menu和菜单项menuitem的公共接口,就能用统一的做法来处理菜单menu和菜单项menuitem,然后分别实现menu和menuitem。

 1 public abstract class menucomponent {
 2     public void add(menucomponent menucomponent){
 3         throw new unsupportedoperationexception();
 4     }
 5     public void remove(menucomponent menucomponent){
 6         throw new unsupportedoperationexception();
 7     }
 8     public menucomponent getchild(int i){
 9         throw new unsupportedoperationexception();
10     }
11     
12     public string getname(){
13         throw new unsupportedoperationexception();
14     }
15     public string getdescription(){
16         throw new unsupportedoperationexception();
17     }
18     public double getprice(){
19         throw new unsupportedoperationexception();
20     }
21     public boolean isvegetarian(){
22         throw new unsupportedoperationexception();
23     }
24     
25     public void print(){
26         throw new unsupportedoperationexception();
27     }
28 }

 1 public class menuitem extends menucomponent{
 2     //和以前一样的省略
 3     ...
 4     //超类中的所有方法都是默认实现,只有需要更改的子类中才覆盖
 5     public void print(){
 6         system.out.print("  "+getname());
 7         if(isvegetarian()){
 8             system.out.print("(v)");
 9         }
10         system.out.println(","+getprice());
11         system.out.print("  ---"+getdescription());
12     }
13 }

 1 import java.util.arraylist;
 2 import java.util.iterator;
 3 public class menu extends menucomponent{
 4     arraylist menucomponents = new arraylist();
 5     string name;
 6     string description;
 7     public menu(string name, string description) {
 8         super();
 9         this.name = name;
10         this.description = description;
11     }
12     
13     public void add(menucomponent menucomponent){
14         menucomponents.add(menucomponents);
15     }
16     public void remove(menucomponent menucomponent){
17         menucomponents.remove(menucomponents);
18     }
19     public menucomponent getchild(int i){
20         return (menucomponent) menucomponents.get(i);
21     }
22     
23     public string getname(){
24         return name;
25     }
26     public string getdescription(){
27         return description;
28     }
29     
30     public void print(){
31         system.out.print("\n"+getname());
32         system.out.print("  ---"+getdescription());
33         system.out.print("----------------------------");34     }
35 }

 1 import java.util.arraylist;
 2 import java.util.iterator;
 3 public class waitress {
 4     //waitress需要接触的只有最上层菜单,一个元素。
 5     menucomponent allmenus;
 6 
 7     public waitress(menucomponent allmenus) {
 8         super();
 9         this.allmenus = allmenus;
10     }
11 
12     public void printmenu(){
13         allmenus.print();
14     }
15 }

 1 public class menutestdrive {
 2     public static void main(string[] args){
 3         menucomponent allmenus = new menu("all menus","all menus together");
 4         
 5         menucomponent pancakehousemenu = new pancakehousemenu("pancake menu","breakfast");
 6         menucomponent dinermenu = new dinermenu("diner menu","lunch");
 7         menucomponent cafemenu = new cafemenu("cafe menu","cafe");
 8         menucomponent dessertmenu = new dessertmenu("dessert menu","dessert");
 9         
10         //additem的就略了
11 
12         dinermenu.add(dessertmenu);
13       
14         allmenus.add(pancakehousemenu);
15         allmenus.add(dinermenu);
16         allmenus.add(cafemenu);
17         
18         waitress waitress = new waitress(allmenus);
19         waitress.printmenu();
20     }
21 }

8.如何使用迭代器遍历整个组合:(有错误,没找出原因)

为了实现遍历封装,在menucomponent中添加createiterator,并且在item和menu中都分别实现各自的iterator。这里用到了nulliterator,如果不这样,而是return null,这样客户代码就不需要if来判断返回值是否为null。(前面也出现过这种手法,就是建立一个什么都不做的方法或者类,这样就不用if判断了)

 1 //之前的menu
 2 public void print(){
 3         system.out.print("\n"+getname());
 4         system.out.print("  ---"+getdescription());
 5         system.out.print("----------------------------");
 6 }
 7 
 8 //现在的menu
 9 public void print(){
10         system.out.print("\n"+getname());
11         system.out.print("  ---"+getdescription());
12         system.out.print("----------------------------");
13         //递归遍历
14         iterator iterator = menucomponents.iterator();
15         while(iterator.hasnext()){18             //在这里出现了错误:java.util.arraylist cannot be cast to unit6.iterator.menucomponent
19             menucomponent menucomponent = (menucomponent) iterator.next();
20             menucomponent.print();//如果下面还有子菜单,会递归调用,直至到菜单项而非菜单
21         }
22     }

 1 import java.util.iterator;
 2 
 3 public abstract class menucomponent{
 4     ...
 5     public abstract iterator createiterator();
 6 }
 7 
 8 public class menuitem extends menucomponent{
 9     ...
10     public iterator createiterator(){
11         return new nulliterator();
12     }
13 }
14 
15 public class menu extends menucomponent{
16     ...    
17     public void print(){
18         system.out.print("\n"+getname());
19         system.out.print("  ---"+getdescription());
20         system.out.print("----------------------------");
21         //递归遍历
22         iterator iterator = menucomponents.iterator();
23         while(iterator.hasnext()){ 26             //在这里出现了错误:java.util.arraylist cannot be cast to unit6.iterator.menucomponent
27             menucomponent menucomponent = (menucomponent) iterator.next();
28             menucomponent.print();//如果下面还有子菜单,会递归调用,直至到菜单项而非菜单
29         }
30     }
31     
32     public iterator createiterator(){
33         //return menucomponents.iterator();
34         return new compositeiterator(menucomponents.iterator());
35     }
36 }

 1 public class compositeiterator implements iterator {
 2     stack stack = new stack();
 3     public compositeiterator(iterator iterator) {
 4         stack.push(iterator);
 5     }
 6 
 7     public boolean hasnext() {
 8         if(stack.empty()){
 9             return false;
10         }else{
11             iterator iterator = (iterator) stack.peek();
12             if(!iterator.hasnext()){
13                 stack.pop();
14                 return hasnext();
15             }else{
16                 return true;
17             }
18         }
19     }
20 
21     public object next() {
22         if(hasnext()){
23             iterator iterator = (iterator) stack.peek();
24             menucomponent component = (menucomponent) iterator.next();
25             if(component instanceof menu){
26                 stack.push(component.createiterator());
27             }
28             //一定要返回component,不然又会出现类型错误
29             return component;
30         }else{
31             return null;
32         }
33         
34     }
35 
36     public void remove() {
37         throw new unsupportedoperationexception();
38     }
39 
40 }

 1 public class nulliterator implements iterator {
 2 
 3     public boolean hasnext() {
 4         return false;
 5     }
 6 
 7     public object next() {
 8         return null;
 9     }
10 
11     public void remove() {
12         throw new unsupportedoperationexception();
13     }
14 
15 }

综上所述:当你有数个对象的集合(collection),他们彼此之间有整体和部分的关系,并且你想要用一致的方式对待这些对象,就使用组合模式。

headfirst学习笔记之九:迭代器与组合模式(5.1)

原文地址:http://www.cnblogs.com/liyuhui21310122/p/4471427.html

软件教程库 原文链接:https://www.itjcku.com/9999/1091413.html

阅读全部内容


Tags:学习笔记迭代器组合模式

返回首页



推荐内容

IOSapplicationWillResignActive

一、挂起当有电话进来或者锁屏,这时你的应用程会挂起,在这时,uiapplicationdelegate委托会收到通知,调 ...

哥我要向前看了

七年前的五一节前的那个周六,我遇到生命中一个重要的人。虽然相处短暂,好梦不长,但是回忆丰满,念念不忘。 七年后的五一节, ...

GoldSmith第二章

uhf:特高频 300m-3000mhz shf:超高频 3g-30g 所有发射与接收的信号都是实信号(因为调制器的振荡 ...

动态规划总结【模板】

最长递增子序列 给定一个序列,找到最长子序列的长度,使得子序列中的所有元素被排序的顺序增加。 1.求最长递增子序列的 ...

HDUACM1103Flo'sRestaurant

分析:借助stl的min_element实现。每次更新最先被占用的桌子,具体见注释。 #includelt;iostre ...

【翻译自mos文章】Oracledb12c中,每次日志切换时,会改变alert_sid.log的权限

12c中,每次日志切换时,会改变alert_sid.log的权限 来源于: alert log file‘s perm ...

poj1988(并查集)

题意:有30000个木块,编号从1到30000,然后有两种操作m a b,把木块a所在的堆块放到木块b所在的堆块上,操作 ...

org.hibernate.exception.GenericJDBCException:Couldnotopenconnection

1、错误描述 org.hibernate.exception.genericjdbcexception: could ...

ubuntu下mysql导出数据

使用的是workbench,原因时workbench的导出工具mysqldump和mysql的版本不一致,这个时候手动指 ...

怎样看懂女人哪些最直接的肢体暗示,撒娇

主动拥抱。 拥抱是最简单却十分亲密的身体接触,女人在想亲热时,会主动寻求拥抱,向伴侣靠近。如果她躺在你的怀抱中,并用语言 ...

移动后端云平台Bmob介绍

对于移动端的独立开发者来说,最痛苦的事情莫过于搭建后台服务器。没有基础的还得从头学起,有技术的又要搭建维护后台,非常 ...

WAMP配置虚拟主机

问题背景:从网上下载了一个php项目a,a项目需要部署在网站的根目录下。配置虚拟主机可以解决这个问题。1.打开apach ...

java克隆测试

1.person类 1 //clone方法必须实现cloneable接口 2 public class perso ...

C++string中用于查找的find系列函数浅析

总述:以下所讲的所有的string查找函数,都有唯一的返回类型,那就是size_type,即一个无符号整数(按打印出来的 ...

Savingoutputofagrepintoafilewithcolors

19 down vote favorite 7 i need to save the result o ...

hibernate异常之QueryException

org.hibernate.queryexception: expected positional parameter ...

Redis的Python客户端redis-py的初步使用

1. 安装 sudo pip install redis sudo pip install hiredis pa ...

《构建高性能Web站点》笔记

书名:构建高性能web站点 出版社: 电子工业出版社 isbn:9787121170935 一 绪论 等待的时间: ( ...

制作OSX10.10.3启动安装U盘

1.获得install os xyosemite.app 2.准备一个8gb的u盘,用磁盘工具抹掉,格式默认的mac o ...

域名解析URL转发

url转发 转发功能:如果您没有一台独立的服务器(也就是没有一个独立的ip地址)或者您还有一个域名b,您想访问a域名时访 ...

instancetypeVSid

英文好的直接读下面链接的文章就好了: http://stackoverflow.com/questions/897222 ...

androidapp开发感想

这几天帮学长做app的时候,照着视频学了json数据的传递,接着遇到了问题,就是httpurlconnection会 ...

常用软件及注册码

vmware-workstation-full-11.0.0-2305329.exe m50ac-j034j-08l8a ...

[POJ3420]QuadTiling

quad tiling time limit:1000ms memory limit:65536k to ...

C-关键字,标识符,注释

一.关键字:c语言中提供了有特殊含义的符号,也叫做保留字。 c语言中一个32个关键字,这些关键字都被赋予了 ...

C-基本概念

一.程序结构 1.c 程序结构:任何一个c程序都是由一个或小个程序代码块组成,每个小程序都有自己的功能,一般称这些小 ...

应该具备的能力

1. 学习能力(learning ability)   有些东西不懂很正常,从不懂到懂,从懂到精通,自己想想,原来不会的 ...

Apache-rhel5.8环境下编译安装

apache安装过程 step 1:安装包gcc或gcc-c++# yum install gcc#yum insta ...

OpenWrt学习目标

最近在研究openwrt,总感觉这一看一点那也了解一点,没有目的,也没有重心。 这里,给自己拟定一个目标,就朝着这个目标 ...

HelloKiki(hdu3579+不互质的中国剩余定理)

hello kiki time limit:1000msmemory limit:32768kb64bit io ...


本网站部分内容来自互联网,版权归原作者所有,文章内容仅代表原作者个人观点。如有侵权请联系我们删除 电子邮件 itjcku@foxmail.com