#1
아래 클래스는 Tree Item 을 표현하였다.
public class TreeItem
{
public TreeItem Before { get; private set; }
private readonly List<TreeItem> nexts = new List<TreeItem>();
public IEnumerable<TreeItem> Nexts => this.nexts;
public string Name { get; }
public TreeItem(string name)
{
this.Name = name;
}
public void AddNext(TreeItem item)
{
this.nexts.Add(item);
item.Before = this;
}
public IEnumerable<TreeItem> BeforeStream()
{
//
}
public IEnumerable<TreeItem> NextStream()
{
//
}
}
Before는 부모 노드 이며 Nexts 자식 노드들이다.
메서드 BeforeStream() 은 모든 부모들을 검색한다.
메서드 NextStream() 은 모든 자식들을 검색한다.
이 두
메서드를 지연 반환(yield return)을 이용하여 작성 하고 아래와 같은 결과를 출력한다.
public static void Test()
{
TreeItem root = new TreeItem("root");
TreeItem level1 = new TreeItem("level1");
TreeItem level2 = new TreeItem("level2");
TreeItem level1_1 = new TreeItem("level1_1");
TreeItem level1_2 = new TreeItem("level1_2");
TreeItem level2_1 = new TreeItem("level2_1");
TreeItem level2_2 = new TreeItem("level2_2");
TreeItem level2_3 = new TreeItem("level2_3");
root.AddNext(level1);
root.AddNext(level2);
level1.AddNext(level1_1);
level1.AddNext(level1_2);
level2.AddNext(level2_1);
level2.AddNext(level2_2);
level2.AddNext(level2_3);
Console.WriteLine("root nexts:");
foreach (var item in root.NextStream())
{
Console.WriteLine(item.Name);
}
Console.WriteLine();
Console.WriteLine("level1_2 befores:");
foreach (var item in level1_2.BeforeStream())
{
Console.WriteLine(item.Name);
}
var found = root.NextStream().First(i => i.Name == "level1_1");
Console.WriteLine("");
Console.WriteLine("found:");
Console.WriteLine(found.Name);
}
결과:
root nexts:
level1
level1_1
level1_2
level2
level2_1
level2_2
level2_3
level1_2 befores:
level1
root
found:
level1_1
#2
작성한 두 메서드(BeforeStream, NextStream)를 다른 곳 에서도 사용 할 수 있도록 하자.
아래와 같이 조직도를 표현하기 위한 Group(조직) 이라는 Entity 가 있다.
Group은 GroupBase라는 클래스를 상속 받고 있으므로 해당기능은
인터페이스로 정의하고 확장메서드를 이용하여 작성한다. 작성한 인터페이스를 Group에 적용 시킨다. (결과는 #1과 동일)
public class GroupBase
{ }
public class Group : GroupBase
{
public Group Before { get; private set; }
private readonly List<Group> nexts = new List<Group>();
public IEnumerable<Group> Nexts => this.nexts;
public string Name { get; }
public Group(string name)
{
this.Name = name;
}
public void AddNext(Group group)
{
this.nexts.Add(group);
group.Before = this;
}
}
/*답*/
ITreeSearch<T> 를 작성하고 이를 확장하여 BeforeStream, NextStream 을 작성하였다.
Group 에 Tree Search 기능 추가.
public class Group : GroupBase, ITreeSearch<Group>
수정 할 수 없는 다른 에셈블리에 아래와 같은 클래스가 있다면
public class ClassInOtherAssembly
{
public ClassInOtherAssembly Parent { get; }
public IEnumerable<ClassInOtherAssembly> Children { get; }
}
아래와 같이 기능을 추가 할 수 있다.
public class ClassInOtherAssemblyExt : ClassInOtherAssembly, ITreeSearch<ClassInOtherAssembly>
{
public ClassInOtherAssembly Before => this.Parent;
public IEnumerable<ClassInOtherAssembly> Nexts => this.Children;
}
다음은 작성한 ITreeSearch<T>와 TreeSearchExtensions 이다.
public interface ITreeSearch<T>
{
T Before { get; }
IEnumerable<T> Nexts { get; }
}
public static class TreeSearchExtensions
{
public static IEnumerable<T> BeforeStream<T>(this ITreeSearch<T> treeSearch) where T : ITreeSearch<T>
{
var current = treeSearch.Before;
while (current != null)
{
yield return current;
current = current.Before;
}
}
public static IEnumerable<T> NextStream<T>(this ITreeSearch<T> treeSearch) where T : ITreeSearch<T>
{
foreach (var next in treeSearch.Nexts)
{
yield return next;
foreach (var item in NextStream(next))
{
yield return item;
}
}
}
}
제약 조건으로 형식 T 는 ITreeSearch<T> 임을 정의 하여 검색된 Before 와 Next 가 ITreeSearch<T> 임을 나타 내었다.
재사용 가능한 메서드를 Interface 확장을 통해 작성 해 보았다.