Частина тексту файла (без зображень, графіків і формул):
Міністерство освіти та науки України
Національний університет ”Львівська політехніка”
ІКТА
Кафедра СКС
Лабораторна робота №3
з дисципліни «Проектування контролерів периферійних пристроїв »
Львів 2014
Тема: Ознайомлення з Патерном Ітератор — Iterator
Мета: Навчитися реалізовувати та застосовувати патерн Ітератор — Iterator
Уявіть, що ви розробник статегічної воєнної гри. Армія має складну структуру: вона складається із героя і трьох груп. Коли генерал видає указ і ресурси щоб полікувати всіх воїнів (герой також є воїном), ви хочете проітерувати по всіх солдатах і викликати метод Treat() на кожному екземплярі. Як це можна зробити легко і без вникання в структуру армії?
Ітератор дозволяє доступатися почергово до елементів будь-якої колекції без вникання в суть її імплементації.
Таким чином в застосуванні до нашої проблеми, ми хочемо щоб SoldiersIterator «пробігся» по всіх солдатах. Код нище показує використання Ітератора.
var iterator = new SoldiersIterator(earthArmy);
while (iterator.HasNext())
{
var currSoldier = iterator.Next();
currSoldier.Treat();
}
Як бачимо, ми отримали екземпляр класу ітератора SoldiersIterator. І простим циклом проходимося по всіх солдатах армії. Це дуже легко, що і є основним завданням ітератора.Армія складається із одного героя і може містити багато груп, кожна із яких може містити багато солдатів. Отже, як ми бачимо, сктуктура армії складна і деревовидна. Код нижче показує створення армії:
var andriybuday = new Hero("Andriy Buday");
var earthArmy = new Army(andriybuday);
var groupA = new Group();
for (int i = 1; i < 4; ++i) groupA.AddNewSoldier(new Soldier("Alpha:" + i));
var groupB = new Group();
for (int i = 1; i < 3; ++i) groupB.AddNewSoldier(new Soldier("Beta:" + i));
var groupC = new Group();
for (int i = 1; i < 2; ++i) groupC.AddNewSoldier(new Soldier("Gamma:" + i));
earthArmy.AddArmyGroup(groupB);
earthArmy.AddArmyGroup(groupA);
earthArmy.AddArmyGroup(groupC);
Герой (Hero) — це клас унаслідуваний від солдата (Soldier) і основна різниця полягає в тому, що він має вищий початковий рівень здоров’я.
class Soldier
{
public String Name;
public int Health;
private const int SoldierHealthPoints = 100;
protected virtual int MaxHealthPoints { get { return SoldierHealthPoints; } }
public Soldier(String name)
{
Name = name;
}
public void Treat()
{
Health = MaxHealthPoints;
Console.WriteLine(Name);
}
}
class Hero : Soldier
{
private const int HeroHealthPoints = 500;
protected override int MaxHealthPoints { get { return HeroHealthPoints; } }
public Hero(String name)
: base(name)
{
}
}
То ж, якщо ми можемо рухатися по складній колекції так легко, де ж вся складність? Звісно, вона інкапсульована в конкретному класі ітератора.
class SoldiersIterator
{
private readonly Army _army;
private bool _heroIsIterated;
private int _currentGroup;
private int _currentGroupSoldier;
public SoldiersIterator(Army army)
{
_army = army;
_heroIsIterated = false;
_currentGroup = 0;
_currentGroupSoldier = 0;
}
public bool HasNext()
{
if (!_heroIsIterated) return true;
if (_currentGroup < _army.ArmyGroups.Count) return true;
if (_currentGroup == _army.ArmyGroups.Count - 1)
if (_currentGroupSoldier < _army.ArmyGroups[_currentGroup].Soldiers.Count)
return true;
return false;
}
public Soldier Next()
{
Soldier nextSoldier;
if (_currentGroup < _army.ArmyGroups.Count)
{
// В кожній групі ітеруємо по кожному солдату
if (_currentGroupSoldier < _army.ArmyGroups[_currentGroup].Soldiers.Count)
{
nextSoldier =
_army.ArmyGroups[_currentGroup].Soldiers[_currentGroupSoldier];
_currentGroupSoldier++;
}
else
{
_currentGroup++;
_currentGroupSoldier = 0;
return Next();
}
}
// Герой останнім покидає поле бою
else if (!_heroIsIterated)
{
_heroIsIterated = true;
return _army.ArmyHero;
}
else
{
// Викидуємо виняток
throw new Exception("End of colletion");
}
return nextSoldier;
}
}
Цей приклад дещо відхиляється від стандартного. Я собі поставив за мету підкреслити головне завдання, яке вирішує паттерн. Головною різницею між моїм поясненням і тоннами інших пояснень є те, що стандартні є більш абстраговані. Я створював потрібний нам ітератор таким чином:
var iterator = new SoldiersIterator(earthArmy);
Але зазвичай створення ітератора також інкапсулюється під методом агрегата. Це потрібно в тих ситуаціях, коли ми хочемо мати декілька різних ітераторів (скажімо, ще один тільки для героїв). Мій код міг би виглядати так:
AbstractIterator iterator = AbstractArmy.GetSoldiersIterator();
var list = new List<int>();
// GetEnumerator це метод інтерфейсу IEnumerable (агрегат)
var enumerator = list.GetEnumerator();
// MoveNext метод інтерфейсу IEnumerator і буде методом ітератора
enumerator.MoveNext();