2022. 3. 15. 00:00ㆍCSharp/Design Pattern
기반이 되는 표현을 노출시키지 않고 연속적으로 객체 요소에 접근하는 방법을 제공하는 것
다시말해 aggregate 유형에 무관한 동일 순차 접근 방법을 제공하는것이며 , 여기서 aggregate란 반복자객체를 생성하기위한 인터페이스를 정의하는것이고 iterator 란 요소에 접근 할 수 있고 순회 할 수 있는 인터페이스를 정의하는것이다.
문제
컬렉션의 각 요소에 순차적으로 액세스할 수 있는 방법이 필요할때list 같은 collection 이라면 쉬운 작업일 수 있으나 복잡한 트리 구조라면 이야기가 달라진다.또 해당 tree 를 깊이 우선으로 탐색 할지 너비 우선으로 탐색 할지에 따라 방법도 달라진다.
해결책
컬렉션의 순회 동작 자체를 iterator 라는 별도의 객체로 추출하는 것
Iterator 는 다양한 순회 알고리즘을 구현하고 여러 반복자 개체가 같은 컬렉션을 동시에 순회할 수 있다.
또한 현재 위치 및 끝까지 남은 요소 수와 같은 모든 탐색 세부 정보를 캡슐화
class diagram
적용
컬렉션의 내부에 복잡한 데이터 구조가 있지만 그 복잡성을 클라이언트로부터 숨기고 싶은 경우
앱 전체에서 순회 코드의 중복을 줄이고 싶을때
코드가 다른 데이터 구조를 순회할 수 있기를 원하거나 이러한 구조의 유형을 미리 알 수 없는 경우
간단하게 주(weeks) 라는 aggregate (collection) 를 만들고 해당 aggregate 을 순회하는 interator를 만들어 보자
Iterator 정의
public interface IWeeksIterator //Iterator interface
{
string Current { get; }
bool MoveNext();
}
public class WeeksIterator : IWeeksIterator //Iterator object
{
private readonly string[] weeks;
private int position;
public WeeksIterator(string[] weeks)
{
this.weeks = weeks;
this.position = -1;
}
public string Current => weeks[position];
public bool MoveNext()
{
if (++position == weeks.Length) return false;
return true;
}
}
Aggregate (Collection) 정의
public class Weeks //Aggregate object
{
private string[] weeks = new string[]{
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
};
public IWeeksIterator GetWeeksIterator()
{
//creates an Iterator object
return new WeeksIterator(weeks);
}
}
사용법
var weeks = new Weeks();
var iterator = weeks.GetWeeksIterator();
while (iterator.MoveNext())
{
Console.WriteLine(iterator.Current);
}
//output
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
위와 같은 경우 client 쪽의 코드를 수정하지 않고 순회 하는 방식을 바꾸려면
다른 iterator 를 구현 하면 된다.
// 평일용 iterator
public class WeekDaysIterator : IWeeksIterator
{
private readonly string[] weeks;
private int position;
public WeekDaysIterator(string[] weeks)
{
this.weeks = weeks;
this.position = -1;
}
public string Current => weeks[position];
public bool MoveNext()
{
if (++position == (weeks.Length - 2)) return false;
return true;
}
}
//output
Monday
Tuesday
Wednesday
Thursday
Friday
또한 C# 에서는 yield 구문을 통해 아주 간단하게 iterator 를 구현 할 수 있다.
yield 구문과 IEnumerable 을 통하여 구현 하는 Iterator
public class Weeks
{
private string[] weeks = new string[]{
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
};
public IEnumerable GetWeeksIterator()
{
foreach (var item in weeks)
{
yield return item;
}
}
public IEnumerable GetWeekDaysIterator()
{
for (int i = 0; i < (weeks.Length - 2); i++)
{
yield return weeks[i];
}
}
}
사용법
var weeks = new Weeks();
foreach (var item in weeks.GetWeeksIterator())
{
Console.WriteLine(item);
}
Console.WriteLine();
foreach (var item in weeks.GetWeekDaysIterator())
{
Console.WriteLine(item);
}
// output
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
weeks (aggregate) 가 IEnumerable 을 직접 implements 하는 경우
public class Weeks : IEnumerable
{
private string[] weeks = new string[]{
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
};
public IEnumerator GetEnumerator()
{
foreach (var item in weeks)
{
yield return item;
}
//for (int i = 0; i < (weeks.Length - 2); i++)
//{
// yield return weeks[i];
//}
}
}
사용법
var weeks = new Weeks();
foreach (var item in weeks)
{
Console.WriteLine(item);
}
//output
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
관련영상
'CSharp > Design Pattern' 카테고리의 다른 글
State (0) | 2022.03.17 |
---|---|
Memento (0) | 2022.03.16 |
Chain of Responsibility (0) | 2022.03.14 |
Proxy (0) | 2022.03.11 |
Flyweight (0) | 2022.03.11 |