8. 4 구현
복합체 패턴의 예제 프로그램을 구현하는 순서는 Tree, Category, Path, 데모 코드 순으로 하겠습니다.
8.4.1 Tree
Tree 클래스는 Path와 Category를 같은 방법으로 사용할 수 있게 하려고 Path에서 수행할 수 있는 기능과 Category에서 할 수 있는 모든 기능에 대해 약속 또는 구현해 주어야 합니다.
Path에서는 자신의 정보를 보여주는 기능이 필요합니다. Category에서는 자신의 정보 및 자식 요소들에 대한 정보를 보여주는 기능이 필요합니다. 이에 대한 구체적 구현이 추상 메서드로 약속만 하겠습니다.
또한, Category에서는 자식 요소를 추가하거나 제거할 수 있는 기능을 제공해 주어야 할 것입니다. 하지만 단일 개체인 Path에서는 이에 대해 재정의할 것이 없으므로 Tree 클래스에는 메서드 내부를 비어있게 구현할게요. 물론, Category에서는 재정의해야 합니다. 이처럼 Path에서는 불필요한 기능까지 기반 클래스에서 제공하는 것은 복합체 패턴의 단점입니다.
▶ Tree.cs
namespace Composite { abstract class Tree { public string Name { get; private set; } public Tree Parent { get; set; } public abstract void View(); public virtual void AddChild(Tree child) //복합 개체에서만 필요한 기능 { } public virtual void RemoveChild(Tree child) //복합 개체에서만 필요한 기능 { } public int Size { get { return Name.Length + Level*2; } } public int Level { get { int level = 0; Tree ancestor = Parent; while(ancestor!=null) { level++; ancestor = ancestor.Parent; } return level; } } public Tree(string name) { Name = name; Parent = null; } } }
8.4.2 Category
Category 클래스에서는 자신의 정보 및 자식 요소들의 정보도 보여주도록 View 메서드를 재정의해야 할 것입니다. 그리고 자식 요소를 추가하거나 자식 요소를 제거하는 메서드도 재정의해야 합니다.
▶ Category.cs
using System; using System.Collections.Generic; namespace Composite { class Category:Tree { List<Tree> children = new List<Tree>(); public Category(string name):base(name) { } public override void View() { Console.WriteLine("{0," + Size.ToString() + "}-C", Name); foreach(Tree child in children) { child.View(); } } public override void AddChild(Tree child) //Category에만 필요한 기능 { child.Parent = this; children.Add(child); } public override void RemoveChild(Tree child) //Category에만 필요한 기능 { child.Parent = null; children.Remove(child); } } }
8.4.3 Path
Path 클래스에서는 단순히 자신의 정보를 보여주는 View 메서드를 재정의하면 되겠죠.
▶ Path.cs
using System; namespace Composite { class Path:Tree { public Path(string path):base(path) { } public override void View() { Console.WriteLine("{0," + Size.ToString() + "}", Name); } } }
8.4.4 데모 코드
데모 코드에서는 지역별로 관리되는 서브 트리와 날짜별로 관리되는 서브 트리를 구성된 트리를 만들고 이들에 대한 전체 정보를 보여주는 정도로 보여주려고 합니다.
▶ Program.cs
namespace Composite { class Program { static void Main(string[] args) { Tree tree = new Category("사진트리"); Tree date_tree = MakeDemoDateTree(); Tree location_tree = MakeDemoLocationTree(); tree.AddChild(date_tree); tree.AddChild(location_tree); tree.View(); } static Tree MakeDemoLocationTree() { Tree tree = new Category("지역"); Tree sub1 = new Category("제주"); Tree sub2 = new Category("천안"); Tree sub3 = new Category("서울"); Tree sub4 = new Path("C:\\사진\\외도"); Tree sub2_1 = new Path("C:\\사진\\현충사의봄"); sub2.AddChild(sub2_1); tree.AddChild(sub1); tree.AddChild(sub2); tree.AddChild(sub3); tree.AddChild(sub4); return tree; } static Tree MakeDemoDateTree() { Tree tree = new Category("날짜"); Tree sub1 = new Category("20120429"); Tree sub2 = new Category("20120407"); Tree sub3 = new Category("20120507"); Tree sub1_1 = new Path("C:\\사진\\외도"); sub1.AddChild(sub1_1); Tree sub2_1 = new Path("C:\\사진\\현충사의봄"); sub2.AddChild(sub2_1); Tree sub3_1 = new Path("C:\\사진\\일산고구마모종"); sub3.AddChild(sub3_1); tree.AddChild(sub1); tree.AddChild(sub2); tree.AddChild(sub3); return tree; } } }
▶ 실행 결과
사진트리-C 날짜-C 20120429-C C:\사진\외도 20120407-C C:\사진\현충사의봄 20120507-C C:\사진\일산고구마모종 지역-C 제주-C 천안-C C:\사진\현충사의봄 서울-C C:\사진\외도