イテレータ

(事前にロシア語でごめんなさい)

あなたが戦略的な戦争ゲームの開発者であると想像してください。 軍隊は複雑な構造をしています。ヒーローと3つのグループで構成されています。 王がすべての戦士(ヒーローも戦士)を癒すための命令とリソースを発行するとき、すべての兵士を操作し、各インスタンスで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 .


軍隊の構造



軍隊は1人のヒーローで構成され、複数のグループが含まれることがあり、各グループには多くの兵士が含まれることがあります。 ですから、私たちが見るように、軍隊の構造は複雑で木に似ています。 以下のコードは、軍隊の作成を示しています。

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とどう違うのですか?



このパターンが解決する主なタスクを強調し、すべてが簡単に見えるようにそれを行うタスクを自分で設定したからです。 もう1つの理由は、このパターンに関する多くの標準的な説明を読むことができることです。 私の説明と他の説明の主な違いは、標準の説明がより抽象的なことです。

たとえば、次のように必要なイテレータを作成しました。

SoldiersIterator iterator = new SoldiersIterator (earthArmy);

* This source code was highlighted with Source Code Highlighter .


ただし、通常、イテレータの作成も集約メソッド(.NETのGetEnumeratorなど)でカプセル化されます。 私のコードは次のようになります。

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では、IEnumerableの代わりにjava.lang.Iterableが使用されます。これは明らかに直感的な名前です。 マイクロソフトはこの件に関してもっと独創的になりたかっただけだと思います:)。

このリンクから、2つの言語の違いの説明が気に入りました。
http://www.25hoursaday.com/CsharpVsJava.html

マイパターンプレート

Source: https://habr.com/ru/post/J84184/


All Articles