TIL_2025_03_20 브리지 패턴

김효중·2025년 3월 20일

브리지 패턴이란?


브리지 패턴은 클래스들의 집합을 두 개의 개별 추황화를 통해 계층구조로 나누어
각각 독립적으로 개발할 수 있도록 하는 구조 디자인 패턴이다.

문제 상황


예를 들어 빨간색 원, 빨간색 큐브, 파란색 원, 파란색 큐브를 클래스로 만든다고 했을 때 다음과 같이 나눌 수 있다.

도형 클래스

  • 모양(Shape) 속성
  • 색깔(Color) 속성
public enum EColor
{
    Red,
    Blue
}

public enum EShape
{
    Circle,
    Square
}
public class Shape : MonoBehaviour
{
    public EColor color;
    public EShape shape;
}

두개의 속성을 가지는 객체를 만들 수 있을 것이다.

만약 모양과 색깔 별 이름을 바꾸고 메시의 색깔을 바꾸는 처리가 필요하다면 다음과 같이 처리 할 수 있다.

 	private string shapeName;

    private MeshRenderer meshR;

    private void Awake()
    {
        meshR = GetComponent<MeshRenderer>();
    }

    void Start()
    {
        switch (color)
        {
            case EColor.Red:
                meshR.material.color = Color.red;
                shapeName += "[R]";
                break;
            case EColor.Blue:
                meshR.material.color = Color.blue;
                shapeName += "[B]";
                break;
        }

        switch (shape)
        {
            case EShape.Square:
                shapeName += " SpongeBob";
                break;
            case EShape.Circle:
                shapeName += " Stone";
                break;
        }

        gameObject.name = shapeName;
    }

색깔별로 Switch문을 나눈고 모양별로 Switch문을 나누어 따로 처리할 수 있다.
나중에 색깔과 모양이 추가 된다면 enum에 새로운 속성을 추가하고 Switch문에 상황을 추가하고 처리를 추가하는 작업이 필요하다.
추가가 많아지고 종류가 많아지면 이러한 작업 역시 늘어난다.

또한 모든 속성을 사전에 알 필요가 있는 문제점이 있다.
브리지 패턴에서는 이러한 비교를 없애고 객체의 속성을 몰라도 동작을 할 수 있도록 한다.

해결

브리지 패턴에서는 이러한 비교를 없애기 위해 각 속성을 클래스로 바꾼다.
색깔의 기능을 도형에서 사용할 수 있게한다.
이를 위해 색깔과 도형에서 사용할 인터페이스와 부모 클래스를 작성한다.

public interface IColorable
{
    public void PaintColor();
    public string ColorString();
}

public class NewShape : MonoBehaviour
{
    protected string s_name;

    protected IColorable m_Colorable;

    private void Awake()
    {
        m_Colorable = GetComponent<IColorable>();
        Paint();
    }

    protected virtual void Paint()
    {
        m_Colorable.PaintColor();
    }
}

각 색깔은 IColorable를 상속 받아 색깔을 바꾸고 이름을 바꾸는 함수를 구현한다.
도형은 색깔의 색깔을 바꾸는 함수를 실행할 수 있다.

public class TRed : MonoBehaviour, IColorable
{
    public string ColorString()
    {
        return "[R]";
    }

    public void PaintColor()
    {
        GetComponent<MeshRenderer>().material.color = Color.red;
    }
}

각 도형은 색깔의 함수를 통해 이름을 문자열로 받고 이를 실행 시킨다.

public class TCircle : NewShape
{
    void Start()
    {
        s_name = "Stone";
        gameObject.name = $"{m_Colorable.ColorString()} {s_name}";
    }
}

씬 객체에서는 다음과 같이 속성들을 가진다.

다른 예시로는 몬스터의 행동을 조절 할 수 있다.

public class Monster : MonoBehaviour
{
    IMonsterBehaviour monsterBehaviour;
    void Start()
    {
        monsterBehaviour = GetComponent<MonsterBehaviour>();
    }

    // Update is called once per frame
    void Update()
    {
        if(monsterBehaviour != null)
        {
            monsterBehaviour.Move();
        }

    }
}

IMonsterBehaviour를 상속받는 오브젝트가 어떻게 동작하는지에는 상관없이 상위에서는 Move만 호출할 수 있다.
이때에도 여러 움직임에 따른 경우의 수를 상관하지 않고 호출 할 수 있다.
클래스의 크기와 수정에 상관 없이 일관적으로 처리를 할 수 있다.

결과

이러한 구조를 통해 다음과 같은 효과를 얻을 수 있다.

  • 개방/폐쇄 원칙 : 새로운 추상화들과 구현들을 상호 독립적으로 도입할 수 있다.
  • 단일 책임 원칙 : 추상화 한 객체는 자신의 동작에 대해서 책임을 진다.

다양한 속성을 가지고 그것이 늘어날 가능성이 높다면 브리지 패턴을 통해 확장성을 가져갈 수 있다.

profile
도전하는 개발자

0개의 댓글