이번에는 이터레이터 패턴, 반복자 패턴입니다.
컬렉션 객체 안에 들어있는 모든 항목에 접근하는 방식이 통일시킨다면 어떤 종류의 집합체에 대해서도 사용할 수 있는 하나의 함수로 모든 컬렉션을 다룰수있게됩니다.
핵심은 다양한 집합체를 하나의 클래스로 상속받아 관리하며 같은 함수로 내부에 접근을 할 수 있다는 것입니다.
넓게보자면 이전에 포스팅했었던 어댑터패턴과 관통하는 부분이 있을 수 있습니다.
2021.09.30 - [게임 개발/디자인 패턴] - [디자인패턴] 9. 유니티에서의 어댑터 패턴 퍼사드 패턴
가장 기반이 될 Iterator 인터페이스와 저장될 info클래스를 먼저 살펴봅시다.
public interface Iterator
{
// 다음 index에 요소가 있는지 체크
bool HasNext();
// 다음 index의 요소를 반환
Info Next();
// 매개변수에 해당되는 요소를 제거
void Remove(Info _target);
// 전체 길이를 반환
int GetLength();
// 원하는 메소드를 추가해도 된다.
}
// 임의적으로 필요한 요소를 클래스로 만들어 상속시킬 것 입니다.
public class Info
{
public string name = string.Empty;
public int hp = 0;
public int damage = 0;
}
일부러 하나는 List 하나는 배열로 만들어 같은 함수를 사용할 수 있게 구현할 것 입니다.
첫번째로 List로 정리되는 MonsterIterator입니다.
public class MonsterInfo : Info
{
// info를 상속받아 생성자에서 정보 저장
public MonsterInfo(string _name, int _hp)
{
this.name = _name;
this.hp = _hp;
}
}
public class MonsterIterator : Iterator
{
// 몬스터 정보리스트
private List<Info> infos = new List<Info>();
// 인덱스
private int index = -1;
// 다양한 방법이 있지만 빠른 테스트를 위해 배열을 받아 초기화시켜줬습니다.
public MonsterIterator(MonsterInfo[] _array)
{
for (int i = 0; i < _array.Length; i++)
{
this.infos.Add(_array[i]);
}
this.index = 0;
}
// 다음 인덱스에 요소가 있는가
public bool HasNext()
{
bool _hasNext = this.index < this.infos.Count;
return _hasNext;
}
// 다음 인덱스의 요소를 반환
public Info Next()
{
return this.infos[this.index++];
}
// 매개변수로 받은 요소를 제거
public void Remove(Info _target)
{
this.infos.Remove(_target);
}
// 전체 길이 반환
public int GetLength()
{
return this.infos.Count;
}
}
다음은 배열로 정리될 WeaponIterator입니다.
public class WeaponInfo : Info
{
// info를 상속받아 생성자에서 정보 저장
public WeaponInfo(string _name, int _damage)
{
this.name = _name;
this.damage = _damage;
}
}
public class WeaponIterator : Iterator
{
// 무기 정보리스트
private Info[] infos = {};
// 인덱스
private int index = -1;
public WeaponIterator(WeaponInfo[] _array)
{
this.infos = _array;
this.index = 0;
}
public bool HasNext()
{
bool _hasNext = this.index < this.infos.Length;
return _hasNext;
}
public Info Next()
{
return this.infos[this.index++];
}
public void Remove(Info _target)
{
// this.infos.Remove(_target);
}
public int GetLength()
{
return this.infos.Length;
}
}
마지막으로 이터레이터패턴을 활용하기위해 간단하게 iteratorCheck 클래스를 만들었습니다.
실제 구현부입니다.
public class IteratorCheck : MonoBehaviour
{
private MonsterIterator monsterIterator = null;
private WeaponIterator weaponIterator = null;
// 예시를 위한 처음 정보배열들
private MonsterInfo[] monsterInfos = {new MonsterInfo("고블린", 1), new MonsterInfo("스켈레톤", 2), new MonsterInfo("오크", 3), new MonsterInfo("드래곤", 4)};
private WeaponInfo[] weaponInfos = {new WeaponInfo("검", 1), new WeaponInfo("도끼", 2), new WeaponInfo("화살", 3), new WeaponInfo("창", 4)};
void Start()
{
// 생성과 동시에 iterator에 배열 저장합니다.
this.monsterIterator = new MonsterIterator(this.monsterInfos);
this.weaponIterator = new WeaponIterator(this.weaponInfos);
// iterator를 상속받은 monsterIterator, weaponIterator는 같은 함수로 편하게 사용할 수 있다.
this.ShowIterator(this.monsterIterator);
this.ShowIterator(this.weaponIterator);
}
void ShowIterator(Iterator _iterator)
{
// 매개변수로 받은 iterator를 순회하며 정보를 출력해줍니다.
for (int i = 0; i < _iterator.GetLength(); i++)
{
Info info = _iterator.Next();
Debug.Log($"이름: {info.name}, 체력:{info.hp}, 공격력:{info.damage} / 다음 정보 존재: {_iterator.HasNext()}");
}
}
}
위와같이 구현하고 실행하게되면 아래와 같이 디버그로그가 찍히게 됩니다.
각기 다른 배열 혹은 리스트를 하나의 함수로 요소를 호출시킬수있는건 큰 이점인 것 같습니다!
반응형
'게임 개발 > 디자인 패턴' 카테고리의 다른 글
[디자인패턴] 12. 유니티에서 컴포지트 패턴 feat.이터레이터 패턴 (0) | 2021.12.25 |
---|---|
[디자인패턴] 10. 유니티에서 템플릿 메소드 패턴 (2) | 2021.10.26 |
[디자인패턴] 9. 유니티에서의 어댑터 패턴 퍼사드 패턴 (2) | 2021.09.30 |
[디자인패턴] 8. 유니티에서의 커맨드 패턴 (0) | 2021.09.23 |
[디자인패턴] 7. 유니티에서 데코레이터 패턴 (0) | 2021.08.22 |