Composite 패턴이란?

 위키의 내용은 다음과 같다.

컴포지트 패턴(Composite pattern)이란 객체들의 관계를 트리 구조로 구성하여 부분-전체 계층을 표현하는 패턴으로, 사용자가 단일 객체와 복합 객체 모두 동일하게 다루도록 한다.

 

이 문장만 보면 무슨 의미인지 정확하게 와닿지 않아 이해한 내용을 토대로 문장을 재구성하면 다음과 같다.

컴포지트 패턴(Composite pattern)이란 동일한 타입의 객체(child)들을 관리하는 동일한 타입의 객체(composite)를 생성하여 관리하는 객체를 통해 child 객체들을 접근하는 패턴이다.

 

컴포지트 패턴을 적용한 구조를 보면 이렇게 나온다.

컴포지트 패턴 구조

 채널을 보여주는 IChannel 인터페이스가 있다고 할 때 특정 채널을 보여주는 Channel 클래스와 이 클래스들을 하나로 묶어서 관리하는 ChannelComposite 클래스가 있다. 이때 두 클래스의 타입은 모드 IChannel로 같기 때문에 ChannelComposite의 Add를 통해 Channel클래스를 갖고있을수도 있고 또다른 ChannelComposite 객체 자체를 갖고 있을 수 있다는 것이 특징이다.

 

Client는 Show() 메서드를 접근할 때 Channel과 ChannelComposite를 직접적으로 참조하지 않고 인터페이스를 통해 참조하게 되며 ChannelComposite의 Show()는 Channel의 Show() 메서드를 호출하는 역할을 담당하게 된다.

 

Composite 패턴의 활용 방법

 앞서 설명했던 것처럼, 컴포지트 패턴은 모두 같은 타입으로 객체를 생성하기 때문에 객체들간의 관계가 집합형태를 이루기 쉽다는 장점이 있다. 따라서 tree 구조를 만들기 용이한데, 코드를 먼저 보면 다음과 같다.

 

IChannel

// 인터페이스
interface IChannel {
    public void Show();
}

ChannelComposite

// 컴포지트
class ChannelComposite : IChannel {

    //Channel 타입 객체를 리스트 형태로 관리합니다.
    private List<IChannel> channels = new List<IChannel>();

    // Channel 객체의 메소드를 호출합니다.
    public void Show() {
        foreach (IChannel channel : channels) {
            channel.Show();
        }
    }

    // 컴포지트에 Channel을 추가합니다.
    public void add(IChannel channel) {
        channels.add(channel);
    }

    // 컴포지트에 Channel을 제거합니다.
    public void remove(IChannel channel) {
        channels.remove(channel);
    }

}

 

Channel

// child
class Channel : IChannel {

	private string message
    
    public Channel(string message){
        this.message = message
    }

    public void Show() {
        Debug.Log(message);
    }
}

 

이처럼 인터페이스와 클래스가 존재할 때 Client쪽에서 접근하면 아래와 같이 사용할 수 있다.

// Client
public class Program {

    public void ShowChannel(){
    
        // Channel 객체 생성
        Channel channel1 = new Channel("1");
        Channel channel2 = new Channel("2");
        Channel channel3 = new Channel("3");
        Channel channel4 = new Channel("4");
  		Channel channel5 = new Channel("5");
        
        // Composite 객체 생성
        ChannelComposite composite1 = new ChannelComposite();
        ChannelComposite composite2 = new ChannelComposite();
        
        // Composite에 객체 할당
        composite1.Add(channel1);
        composite1.Add(channel2);
        composite1.Add(composite2);
        
        composite2.Add(channel3);
        composite2.Add(channel4);
        composite2.Add(channel5);
        
        //"1" 출력
        channel1.Show()
        
        //"1","2","3","4","5" 출력
        composite1.Show()
        
        //"3","4","5" 출력
        composite2.Show()
    }
}

 

Client가 위의 코드처럼 구성했을 경우 Channel 객체와 ChannelComposite 객체간의 관계는 어떤 형태인지 보면 다음과 같다.

트리 형태의 관계

 

 이처럼 유사한 역할을 수행하는 클래스가 존재하거나 추가로 생길 가능성이 있는 경우 컴포지트 패턴을 활용하여 객체들을 관리한다면 새롭게 구현하기에도 쉬울뿐만 아니라 유지보수의 측면에서도 향상된다는 장점이 있다.