经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
迭代器模式
来源:cnblogs  作者:纳兰小依  时间:2019/10/8 9:27:46  对本文有异议

      迭代器模式提供了一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部实现。

      有过Java编程经验的人对这种模式应该比较熟悉,因为Java内置的许多集合类型:List、Set、Map等都提供了迭代器接口,可以使用统一的方式遍历集合中的元素。下面将通过一个例子说明迭代器的使用场景,并了解一下迭代器模式的原理。

      包子店卖的有包子和饮品,对于包子和饮品的每一个条目,我们用Item来表示,Item只包含name和price两个字段:

  1. 1 public class Item {
  2. 2 private String name;
  3. 3 private double price;
  4. 4
  5. 5 public Item(String name, double price){
  6. 6 this.name = name;
  7. 7 this.price = price;
  8. 8 }
  9. 9
  10. 10 // getters and setters ...
  11. 11 }

      由于包子会不定期更新,所以用一个ArrayList来存储目前所有的包子类别:

  1. 1 public class Bun {
  2. 2 ArrayList<Item> buns;
  3. 3
  4. 4 public Bun(){
  5. 5 buns = new ArrayList<>();
  6. 6
  7. 7 addBun("鲜肉包子", 1.5);
  8. 8 addBun("香菇青菜包子", 1);
  9. 9 addBun("鱼香肉丝包子", 1.5);
  10. 10 }
  11. 11
  12. 12 private void addBun(String name, double price){
  13. 13 Item item = new Item(name, price);
  14. 14 buns.add(item);
  15. 15 }
  16. 16
  17. 17 public ArrayList<Item> getBuns(){
  18. 18 return buns;
  19. 19 }
  20. 20 }

      而饮品则比较固定,一般不会增加新的类型,所以就假设固定成5种好了,对于这种需求,或许我们会选择使用数组来实现:

  1. 1 public class Drink {
  2. 2 Item[] drinks;
  3. 3 int position;
  4. 4 private static final int MAX_SIZE = 5;
  5. 5
  6. 6 public Drink(){
  7. 7 drinks = new Item[MAX_SIZE];
  8. 8 position = 0;
  9. 9
  10. 10 addDrink("豆浆", 2);
  11. 11 addDrink("八宝粥", 2);
  12. 12 addDrink("牛奶", 2.5);
  13. 13 addDrink("银耳汤", 3);
  14. 14 addDrink("豆腐脑", 2);
  15. 15 }
  16. 16
  17. 17 private void addDrink(String name, double price){
  18. 18 Item item = new Item(name, price);
  19. 19 if(position >= MAX_SIZE){
  20. 20 System.err.println("饮品已经满了。。。");
  21. 21 }else{
  22. 22 drinks[position++] = item;
  23. 23 }
  24. 24 }
  25. 25
  26. 26 public Item[] getDrinks(){
  27. 27 return drinks;
  28. 28 }
  29. 29 }

      那么,当我们需要输出早餐店里的所有包子和饮品的时候,需要怎么写呢?我们发现包子和饮品的底层存储不一样,或许都改成ArrayList会简单很多,但是由于代码已经写好了,其他很多地方都会使用上面的代码,所以冒险修改不是一个好选择,只能麻烦一些,针对两种情况分别处理:

  1. 1 public void printItems(){
  2. 2 Bun bun = new Bun();
  3. 3 Drink drink = new Drink();
  4. 4 ArrayList<Item> buns = bun.getBuns();
  5. 5 Item[] drinks = drink.getDrinks();
  6. 6
  7. 7 //输出包子
  8. 8 for(int i=0; i<buns.size(); i++){
  9. 9 Item item = buns.get(i);
  10. 10 System.out.println(item.getName() + ", " + item.getPrice());
  11. 11 }
  12. 12
  13. 13 //输出饮品
  14. 14 for(int i=0; i<drinks.length; i++){
  15. 15 System.out.println(drinks[i].getName() + ", " + drinks[i].getPrice());
  16. 16 }
  17. 17 }

      输出如下:

  1. 鲜肉包子, 1.5
  2. 香菇青菜包子, 1.0
  3. 鱼香肉丝包子, 1.5
  4. 豆浆, 2.0
  5. 八宝粥, 2.0
  6. 牛奶, 2.5
  7. 银耳汤, 3.0
  8. 豆腐脑, 2.0

      这里的打印逻辑的实现有几个问题:①打印方法需要知道包子和饮品的底层实现细节,这不满足封装的要求;②打印的逻辑不能扩展,如果包子店增加了馒头类型,而某位程序员打算使用Set来存储所有的馒头,那么打印方法必须要同步修改。因此,我们要做的就是隐藏底层的逻辑,对外提供统一的遍历接口,不管底层采用什么实现,对外保持一致就行。

      为了保持遍历接口的简单性,我们不打算加入太多的逻辑,具体做法是定义一个迭代器接口,包含next()和hasNext()两个方法:

  1. 1 public interface Iterator {
  2. 2 boolean hasNext();
  3. 3 Item next();
  4. 4 }

      为包子和饮品分别定义对应的迭代器:

  1. 1 public class BunIterator implements Iterator{
  2. 2 ArrayList<Item> items;
  3. 3 int position;
  4. 4
  5. 5 public BunIterator(ArrayList<Item> items){
  6. 6 this.items = items;
  7. 7 position = 0;
  8. 8 }
  9. 9
  10. 10 @Override
  11. 11 public boolean hasNext() {
  12. 12 if(items == null || position >= items.size()){
  13. 13 return false;
  14. 14 }else{
  15. 15 return true;
  16. 16 }
  17. 17 }
  18. 18
  19. 19 @Override
  20. 20 public Item next() {
  21. 21 return items.get(position++);
  22. 22 }
  23. 23
  24. 24
  25. 25 public class DrinkIterator implements Iterator{
  26. 26 Item[] items;
  27. 27 int position;
  28. 28
  29. 29 public DrinkIterator(Item[] items){
  30. 30 this.items = items;
  31. 31 position = 0;
  32. 32 }
  33. 33
  34. 34 @Override
  35. 35 public boolean hasNext() {
  36. 36 if(position >= items.length || items[position] == null){
  37. 37 return false;
  38. 38 }else{
  39. 39 return true;
  40. 40 }
  41. 41 }
  42. 42
  43. 43 @Override
  44. 44 public Item next() {
  45. 45 return items[position++];
  46. 46 }
  47. 47 }

      修改包子和饮品类,只对外提供creatorIterator方法:

  1. 1 public class Bun{
  2. 2 ArrayList<Item> buns;
  3. 3
  4. 4 public Bun(){
  5. 5 buns = new ArrayList<>();
  6. 6
  7. 7 addBun("鲜肉包子", 1.5);
  8. 8 addBun("香菇青菜包子", 1);
  9. 9 addBun("鱼香肉丝包子", 1.5);
  10. 10 }
  11. 11
  12. 12 private void addBun(String name, double price){
  13. 13 Item item = new Item(name, price);
  14. 14 buns.add(item);
  15. 15 }
  16. 16
  17. 17 public Iterator creatorIterator(){
  18. 18 return new BunIterator(buns);
  19. 19 }
  20. 20 }
  21. 21
  22. 22
  23. 23 public class Drink {
  24. 24 Item[] drinks;
  25. 25 int position;
  26. 26 private static final int MAX_SIZE = 5;
  27. 27
  28. 28 public Drink(){
  29. 29 drinks = new Item[MAX_SIZE];
  30. 30 position = 0;
  31. 31
  32. 32 addDrink("豆浆", 2);
  33. 33 addDrink("八宝粥", 2);
  34. 34 addDrink("牛奶", 2.5);
  35. 35 addDrink("银耳汤", 3);
  36. 36 addDrink("豆腐脑", 2);
  37. 37 }
  38. 38
  39. 39 private void addDrink(String name, double price){
  40. 40 Item item = new Item(name, price);
  41. 41 if(position >= MAX_SIZE){
  42. 42 System.err.println("饮品已经满了。。。");
  43. 43 }else{
  44. 44 drinks[position++] = item;
  45. 45 }
  46. 46 }
  47. 47
  48. 48 public Iterator creatorIterator(){
  49. 49 return new DrinkIterator(drinks);
  50. 50 }
  51. 51 }

      接下来使用迭代器写一个新的打印方法:

  1. 1 public class TestIterator {
  2. 2
  3. 3 public static void main(String[] args){
  4. 4 TestIterator test = new TestIterator();
  5. 5 test.printItemsWithIterator();
  6. 6 }
  7. 7
  8. 8 public void printItemsWithIterator(){
  9. 9 Bun bun = new Bun();
  10. 10 Drink drink = new Drink();
  11. 11 Iterator bunIterator = bun.creatorIterator();
  12. 12 Iterator drinkIterator = drink.creatorIterator();
  13. 13 printItemsWithIterator(bunIterator);
  14. 14 printItemsWithIterator(drinkIterator);
  15. 15 }
  16. 16
  17. 17 public void printItemsWithIterator(Iterator iterator){
  18. 18 while(iterator.hasNext()){
  19. 19 Item item = iterator.next();
  20. 20 System.out.println(item.getName() + ", " + item.getPrice());
  21. 21 }
  22. 22 }
  23. 23 }

      输出如下:

  1. 鲜肉包子, 1.5
  2. 香菇青菜包子, 1.0
  3. 鱼香肉丝包子, 1.5
  4. 豆浆, 2.0
  5. 八宝粥, 2.0
  6. 牛奶, 2.5
  7. 银耳汤, 3.0
  8. 豆腐脑, 2.0

      仍然能够完成打印任务,而且使用迭代器模式使得代码简洁了许多,也更容易维护。

      以上简介了迭代器模式的用法,实际上有了Java内部的迭代器实现后,我们不再需要编写自己的迭代器,这里是为了展示迭代器的原理才自己实现。

原文链接:http://www.cnblogs.com/NaLanZiYi-LinEr/p/11629069.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号