Как стать автором
Обновить

Итератор

Время на прочтение5 мин
Количество просмотров56K
(Заранее извините за мой русский)

Представьте, что вы разработчик статегичнои военной игры. Армия имеет сложную структуру: она состоит из героя и трех групп. Когда Король издает указ и ресурсы, чтобы полечить всех воинов (Герой также является воином) Вы хотите проитеруваты по всем солдатам и вызвать метод treat () на каждом инстанси. Как это можно сделать легко и без вникания в структуру армией?

ИТЕРАТОР



Итератор это паттерн позволяющий доступатися к элементам любой коллекции без вникания в суть ее имплементации.
Таким образом в применении к нашей проблеме: Мы не хотим переживать структурой Армии — мы хотим чтобы SoldiersIterator пробежался по всем солдатам.

Красная линия на рисунке — это итератор (по крайней мере как я его себе представляю).



Использование



Код ниже показывает использование итератора. Как видим мы просто получили инстанс итератора SoldiersIterator. И простым циклом проходимося по всем солдатам армии. Это очень легко, что и является основной задачей итератора.

  SoldiersIterator iterator = new SoldiersIterator(earthArmy);
  
  while(iterator.hasNext()){
    Soldier currSoldier = iterator.next();
    currSoldier.treat();
  }

* This source code was highlighted with Source Code Highlighter.


Структура Армии



Армия состоит из одного героя и может содержать несколько групп, каждая из которых может содержать много солдат. Итак, как мы видим, сктуктура армии сложная и древовидная. Код ниже показывает создания Армии:

  Army earthArmy = new Army();
  
  Group groupA = new Group();
  for(int i=1; i<4; ++i)
    groupA.addNewSoldier(new Soldier("Alpha:" + i));
  
  Group groupB = new Group();
  for(int i=1; i<3; ++i)
    groupB.addNewSoldier(new Soldier("Beta:" + i));
  
  Group groupC = new Group();
  for(int i=1; i<2; ++i)
    groupC.addNewSoldier(new Soldier("Gamma:" + i));
  
  earthArmy.ArmyHero = new Hero("Andriy Buday");
  earthArmy.addArmyGroup(groupB);
  earthArmy.addArmyGroup(groupA);
  earthArmy.addArmyGroup(groupC);


* This source code was highlighted with Source Code Highlighter.


Герой (Hero) это класс унаслидуваний от солдата (Soldier) и основная разница такова, что он имеет более высокий уровень здоровья.

public class Soldier {  
  public String Name;
  public int Health;
  protected int maxHealthPoints = 100;
  
  public Soldier(String name){
    Name = name;
  }  
  
  public void treat(){
    Health = maxHealthPoints;
    System.out.println(Name);
  }  
}

public class Hero extends Soldier {
  protected int maxHealthPoints = 500;
  
  public Hero(String name) {
    super(name);
  }
}


* This source code was highlighted with Source Code Highlighter.


SoldiersIterator



Поэтому, если мы можем двигаться по сложной коллекции так легко, где есть вся сложность?
Конечно, она скрыта инкапсулированные в конкретном классе итератора.

public class SoldiersIterator {

  private Army _army;
  boolean heroIsIterated;
  int currentGroup;
  int currentGroupSoldier;

  public SoldiersIterator(Army army) {
    _army = army;
    heroIsIterated = false;
    currentGroup = 0;
    currentGroupSoldier = 0;
  }

  public boolean hasNext() {
    if(!heroIsIterated) return true;
    if(currentGroup < _army.ArmyGroups.size())return true;
    if(currentGroup == _army.ArmyGroups.size()-1)
      if(currentGroupSoldier < _army.ArmyGroups.get(currentGroup).Soldiers.size())return true;
    
    return false;
  }

  public Soldier next() {
    Soldier nextSoldier;
    // we still not iterated all soldiers in current group
    if (currentGroup < _army.ArmyGroups.size()) {
      if (currentGroupSoldier < _army.ArmyGroups.get(currentGroup).Soldiers.size()) {
      nextSoldier = _army.ArmyGroups.get(currentGroup).Soldiers.get(currentGroupSoldier);
      currentGroupSoldier++;
      }
      // moving to next group
      else {
      currentGroup++;
      currentGroupSoldier = 0;
      return next();
      }
    }
    // hero is the last who left the battlefield
    else if (!heroIsIterated) {
      heroIsIterated = true;
      return _army.ArmyHero;
    } else {
      // THROW EXCEPTION HERE
      throw new IllegalStateException("End of colletion");
      //or set all counters to 0 and start again, but not recommended
    }
    return nextSoldier;
  }
}


* This source code was highlighted with Source Code Highlighter.


Чем мой пример отличается от стандартного GoF?



Потому что я себе поставил задачу подчеркнуть главная задача которую решает этот паттерн и сделать это таким образом, что можно будет все легко зрозмиты. Еще одной причиной является то, что вы можете прочитать тонны стандартных объяснений этого паттерна. Главной же разницей между моим объяснением и другими объяснениями является то, что стандартные более абстрагированные.

Например, я создавал нужный нам итератор следующим образом:

  SoldiersIterator iterator = new SoldiersIterator (earthArmy);

* This source code was highlighted with Source Code Highlighter.


Но обычно создания итератора также инкапсулюеться под методом агрегата (как GetEnumerator в. NET). Мой код мог бы выглядеть так:

IIterator iterator = AbstractArmy.GetSoldiersIterator ();

* This source code was highlighted with Source Code Highlighter.


В мире. NET мы интерфейсы IEnumerable и IEnumerator , которые нам помогают в использовании этого паттерна.

  var list = new List <int> ();
  //GetEnumerator is method of IEnumerator (Aggregate)
  var enumerator = list.GetEnumerator ();
  //MoveNext method of IEnumerable (Iterator)
  enumerator.MoveNext ();


* This source code was highlighted with Source Code Highlighter.


В Java мы java.lang.Iterable вместо IEnumerable, что очевидно является более интуитивной названием. Я думаю что Microsoft просто хотели быть более оригинальными в этом вопросе:).

По этой ссылке мне понравились объяснения различий между этими двумя языками:
http://www.25hoursaday.com/CsharpVsJava.html

Моя табличка паттернов

Теги:
Хабы:
Всего голосов 43: ↑12 и ↓31-19
Комментарии19

Публикации

Ближайшие события