1. 컴포지트 패턴이란? 🌳

컴포지트 패턴(Composite Pattern)은 객체를 트리(tree) 구조로 구성하여 부분-전체 계층 구조를 구현하는 데 사용됩니다. 이를 통해 클라이언트는 개별 객체와 복합 객체를 동일하게 다룰 수 있습니다.

이 패턴은 특히 UI 구성 요소파일 시스템처럼 계층적 구조를 가진 시스템에서 유용합니다. 컴포지트 패턴은 단순한 인터페이스를 통해 복잡한 구조를 효율적으로 관리할 수 있게 해줍니다.

출처: 위키

 

2. 컴포지트 패턴의 구성 요소 🧩

  1. Component (구성 요소): 트리 구조에서 공통 인터페이스를 정의합니다.
  2. Leaf (잎 노드): 트리 구조의 말단에 해당하며, 실제 작업을 수행합니다.
  3. Composite (복합 노드): 다른 Leaf 또는 Composite를 자식으로 포함할 수 있으며, 자식 요소에 작업을 위임합니다.

3. 컴포지트 패턴 예제 🎮

Unity3D에서 게임 오브젝트 트리 관리

Unity의 GameObject 트리 구조는 컴포지트 패턴의 대표적인 예입니다. 이를 간단히 구현한 예제를 보겠습니다.

using System;
using System.Collections.Generic;

// Component: 공통 인터페이스
public interface IGameObject
{
    void Render();
}

// Leaf: 단일 요소
public class GameObject : IGameObject
{
    private string _name;

    public GameObject(string name)
    {
        _name = name;
    }

    public void Render()
    {
        Console.WriteLine($"Rendering GameObject: {_name}");
    }
}

// Composite: 자식 요소를 포함하는 복합 객체
public class GameObjectGroup : IGameObject
{
    private List<IGameObject> _children = new List<IGameObject>();

    public void Add(IGameObject gameObject)
    {
        _children.Add(gameObject);
    }

    public void Remove(IGameObject gameObject)
    {
        _children.Remove(gameObject);
    }

    public void Render()
    {
        Console.WriteLine("Rendering GameObjectGroup:");
        foreach (var child in _children)
        {
            child.Render();
        }
    }
}

// 예제 실행
public class Program
{
    public static void Main()
    {
        // Leaf 생성
        var player = new GameObject("Player");
        var enemy = new GameObject("Enemy");

        // Composite 생성 및 Leaf 추가
        var scene = new GameObjectGroup();
        scene.Add(player);
        scene.Add(enemy);

        // Composite 내에 또 다른 Composite 추가
        var uiGroup = new GameObjectGroup();
        var uiElement = new GameObject("HealthBar");
        uiGroup.Add(uiElement);
        scene.Add(uiGroup);

        // 전체 트리 구조 렌더링
        scene.Render();
    }
}

출력 결과

Rendering GameObjectGroup:
Rendering GameObject: Player
Rendering GameObject: Enemy
Rendering GameObjectGroup:
Rendering GameObject: HealthBar

4. 컴포지트 패턴 사용 시 고려할 점 ⚠️

  • 객체의 복잡성: 트리 구조가 너무 깊거나 복잡하면 관리가 어려워질 수 있습니다. 불필요한 계층화를 피해야 합니다.
  • 단일 책임 원칙: 컴포지트 객체는 자식 관리와 작업 위임이라는 두 가지 책임을 가지므로, 적절히 설계해야 책임이 분리됩니다.
  • 성능: 큰 트리 구조에서는 순회를 최소화하는 최적화가 필요할 수 있습니다.

5. 결론 🚀

컴포지트 패턴은 객체를 계층적으로 구성하고, 클라이언트가 개별 요소와 복합 요소를 동일하게 처리할 수 있게 해줍니다. 특히 Unity3D와 같은 게임 엔진에서 UI, 씬 관리 등에 매우 유용하게 활용됩니다. 하지만 설계 단계에서 계층 구조의 복잡성을 신중히 고려해야 합니다.

6. 관련 링크 🔗

반응형

1. 플라이웨이트 패턴이란?

플라이웨이트 패턴은 많은 객체를 생성해야 할 때 메모리를 절약하기 위해 공유할 수 있는 객체를 재사용하는 디자인 패턴입니다. 동일한 데이터는 공유하고, 개별 객체는 고유한 상태만 유지하도록 설계합니다. 주로 게임, 그래픽 애플리케이션 등에서 효율적인 리소스 관리에 사용됩니다.

출처: 위키


2. 플라이웨이트 패턴의 구성 요소

  1. Flyweight (공유 객체): 공유 가능한 객체를 정의합니다.
  2. Intrinsic State (내재 상태): 공유 객체가 공통적으로 가지는 불변 상태입니다.
  3. Extrinsic State (외재 상태): 객체별로 고유한 가변 상태이며, 외부에서 제공됩니다.
  4. Flyweight Factory (팩토리): Flyweight 객체를 관리하며, 중복 생성 방지를 위해 기존 객체를 반환하거나 새로 생성합니다.

3. 플라이웨이트 패턴 예제 (C#)

캐릭터 글자 렌더링 최적화 예제

플라이웨이트 패턴은 텍스트 렌더링에서 자주 사용됩니다. 같은 글자를 여러 번 렌더링할 때, 동일한 글자 객체를 재사용해 메모리를 절약합니다.

using System;
using System.Collections.Generic;

// Flyweight (공유 객체)
public class Character
{
    public char Symbol { get; private set; }  // Intrinsic State
    public string Font { get; private set; }  // Intrinsic State

    public Character(char symbol, string font)
    {
        Symbol = symbol;
        Font = font;
    }

    public void Display(int positionX, int positionY) // Extrinsic State
    {
        Console.WriteLine($"Character: {Symbol}, Font: {Font}, Position: ({positionX}, {positionY})");
    }
}

// Flyweight Factory
public class CharacterFactory
{
    private readonly Dictionary<string, Character> _characters = new();

    public Character GetCharacter(char symbol, string font)
    {
        string key = $"{symbol}_{font}";
        if (!_characters.ContainsKey(key))
        {
            _characters[key] = new Character(symbol, font);
        }
        return _characters[key];
    }
}

// Client Code
class Program
{
    static void Main(string[] args)
    {
        CharacterFactory factory = new CharacterFactory();

        // Reusing 'A' with the same font
        var charA1 = factory.GetCharacter('A', "Arial");
        var charA2 = factory.GetCharacter('A', "Arial");

        charA1.Display(10, 20);
        charA2.Display(30, 40);

        Console.WriteLine(Object.ReferenceEquals(charA1, charA2)); // True
    }
}

4. 플라이웨이트 패턴의 사용 시 주의점 ✅

  1. 상태 구분: 내재 상태와 외재 상태를 명확히 분리해야 합니다. 잘못된 설계는 객체의 불변성을 깨뜨릴 수 있습니다.
  2. 팩토리 관리: Flyweight Factory에서 객체의 생명 주기를 잘 관리해야 메모리 누수를 방지할 수 있습니다.
  3. 적합한 상황: 객체 생성 비용이 크고, 동일한 상태의 객체가 반복될 때 효과적입니다. 객체가 항상 고유 상태를 가진다면 이 패턴은 적합하지 않을 수 있습니다.

5. 결론

플라이웨이트 패턴은 메모리 사용을 최적화하고 객체 생성 비용을 줄이는 강력한 도구입니다. 특히 대규모 애플리케이션에서 성능 병목을 해결하는 데 유용합니다. 하지만 상태 관리와 사용 환경에 주의해야 제대로 된 효과를 볼 수 있습니다. 😊


6. 관련 링크

반응형

+ Recent posts