Dev Base
[Dev Base] 디자인패턴_구조패턴
Yangho
2025. 4. 19. 15:14
1. 어댑터 패턴 (Adapter Pattern)
개요
어댑터 패턴은 호환되지 않는 인터페이스를 맞춰주는 역할을 한다. 기존 클래스를 변경하지 않고 새로운 인터페이스에 적응시키는 방식이다.
목적
- 서로 다른 인터페이스를 사용하는 클래스 간의 호환성 확보
- 레거시 코드 재사용
구조
// 기존 클래스
class OldSystem
{
public void OldRequest() => Console.WriteLine("Old request");
}
// 새 인터페이스
interface INewSystem
{
void Request();
}
// 어댑터
class Adapter : INewSystem
{
private OldSystem oldSystem = new OldSystem();
public void Request() => oldSystem.OldRequest();
}
장점
- 기존 코드 변경 없이 사용 가능
- 인터페이스 호환 문제 해결
단점
- 코드가 복잡해질 수 있음
사용 예시
- 외부 라이브러리 인터페이스 통합
- 게임에서 기존 입력 시스템을 새 입력 시스템에 맞출 때
2. 브리지 패턴 (Bridge Pattern)
개요
브리지 패턴은 구현과 추상화를 분리하여 서로 독립적으로 확장할 수 있도록 한다.
목적
- 구현부와 추상부를 분리하여 독립적 확장 가능
- 클래스 수 증가 억제
구조
interface IRenderer
{
void Render(string shape);
}
class CircleRenderer : IRenderer
{
public void Render(string shape) => Console.WriteLine($"Draw circle: {shape}");
}
abstract class Shape
{
protected IRenderer renderer;
public Shape(IRenderer renderer) { this.renderer = renderer; }
public abstract void Draw();
}
class Circle : Shape
{
public Circle(IRenderer renderer) : base(renderer) { }
public override void Draw() => renderer.Render("Circle");
}
장점
- 추상화와 구현부를 독립적으로 확장 가능
- 유연한 구조
단점
- 구조가 복잡할 수 있음
- 초기 설계 비용이 높음
사용 예시
- 게임에서 다양한 렌더링 방식 지원
- UI 플랫폼 추상화
3. 컴포지트 패턴 (Composite Pattern)
개요
컴포지트 패턴은 부분-전체 계층 구조를 동일하게 처리할 수 있도록 구성하는 패턴이다.
목적
- 단일 객체와 복합 객체를 동일하게 취급
구조
abstract class UIElement
{
public abstract void Render();
}
class Button : UIElement
{
public override void Render() => Console.WriteLine("Render Button");
}
class Panel : UIElement
{
private List<UIElement> children = new List<UIElement>();
public void Add(UIElement child) => children.Add(child);
public override void Render()
{
Console.WriteLine("Render Panel");
foreach (var child in children)
child.Render();
}
}
장점
- 트리 구조 구성에 유리
- 일관된 처리 가능
단점
- 설계가 복잡해질 수 있음
사용 예시
- 게임 UI 계층 구성
- 씬 그래프 트리 구조
4. 데코레이터 패턴 (Decorator Pattern)
개요
데코레이터 패턴은 기존 객체에 기능을 동적으로 추가하는 구조이다.
목적
- 상속 없이 객체에 기능 추가
- 실행 중 기능 확장 가능
구조
interface IWeapon
{
void Attack();
}
class Sword : IWeapon
{
public void Attack() => Console.WriteLine("Swing sword");
}
class FireDecorator : IWeapon
{
private IWeapon weapon;
public FireDecorator(IWeapon weapon) { this.weapon = weapon; }
public void Attack()
{
weapon.Attack();
Console.WriteLine("with Fire");
}
}
장점
- 런타임 동적 확장
- 조합 가능한 기능 확장
단점
- 많은 데코레이터 조합 시 복잡도 증가
- 디버깅 어려움
사용 예시
- 게임에서 무기 강화 시스템
- UI 요소에 효과 추가
5. 퍼사드 패턴 (Facade Pattern)
개요
퍼사드 패턴은 복잡한 서브 시스템을 단순한 인터페이스로 감싸는 방식이다.
목적
- 복잡한 시스템 사용을 쉽게 함
- 클라이언트와 서브 시스템 간 결합도 감소
구조
class AudioSystem
{
public void Init() => Console.WriteLine("Audio Init");
}
class RenderSystem
{
public void Init() => Console.WriteLine("Render Init");
}
class GameEngine
{
private AudioSystem audio = new AudioSystem();
private RenderSystem render = new RenderSystem();
public void Start()
{
audio.Init();
render.Init();
}
}
장점
- 사용이 간편
- 내부 구현 캡슐화
단점
- 퍼사드에 너무 많은 책임이 집중될 수 있음
사용 예시
- 게임 엔진 초기화 코드
- 외부 API 통합
6. 플라이웨이트 패턴 (Flyweight Pattern)
개요
플라이웨이트 패턴은 공통된 데이터를 공유하여 메모리를 절약하는 구조이다.
목적
- 메모리 사용 최소화
- 수많은 객체 생성을 효율적으로 처리
구조
class TreeType
{
public string Name;
public string Texture;
}
class Tree
{
public int X, Y;
public TreeType Type;
}
장점
- 메모리 사용 감소
- 대규모 객체 처리에 적합
단점
- 상태와 공유 데이터 분리 필요
- 코드 복잡도 증가
사용 예시
- 수많은 배경 오브젝트가 반복되는 게임
- 캐릭터 외형 데이터 공유
7. 프록시 패턴 (Proxy Pattern)
개요
프록시 패턴은 다른 객체에 대한 접근을 제어하는 대리 객체를 제공하는 구조이다.
목적
- 접근 제어, 지연 초기화, 캐싱 등 기능 추가
구조
interface IImage
{
void Display();
}
class RealImage : IImage
{
public void Display() => Console.WriteLine("Display real image");
}
class ProxyImage : IImage
{
private RealImage realImage;
public void Display()
{
if (realImage == null)
realImage = new RealImage();
realImage.Display();
}
}
장점
- 접근 제어 용이
- 자원 낭비 방지
단점
- 설계 복잡성 증가
사용 예시
- 게임 리소스의 지연 로딩
- 네트워크 객체 프록시