8. 복합체 패턴(Composite Pattern) 구현

복합체 패턴 프로젝트 다운로드

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:\사진\외도