Object Oriented 프로그래밍에서 협업을 위해 설계를 할때,
내가 작성한 코드, 다른 분께서 작성한 코드를 전달해줄 때 생기는 어려움을 극복하기 위해
디자인 패턴이라는 일종의 의사소통 방법을 사용합니다. (일종의 베스트 프랙티스 이기도 하죠)
Design Patterns
Object Oriented Programming; OOP 에서, 설계한 프로젝트 마다의 이해관계를 좀 더 수월하게 할 수 있도록,
제안된 개념 패턴들을 Design Patterns 라고 부르며, 일종의 코딩 방법론입니다.
위 다자인 패턴을 통해, 코드를 재사용하고, 유연하게 작성하며, 유지보수가 쉽게 만들어지는 것에 도움을 줍니다.
맨 처음 아이디어는 논문 Using Pattern Languages for Object-Oriented Programs(1987) 으로부터 시작됐습니다.
https://c2.com/doc/oopsla87.html
Using Pattern Languages for Object-Oriented Programs
Using Pattern Languages for Object-Oriented Programs Kent Beck, Apple Computer, Inc. Ward Cunningham, Tektronix, Inc. Technical Report No. CR-87-43 September 17, 1987 Submitted to the OOPSLA-87 workshop on the Specification and Design for Object-Oriented P
c2.com
일반적으로 프로그래머가 만나게 되는 문제들은 대체로, 본인이 지구상에서 맨 처음 겪는 문제가 아닐 확률이 높습니다.
많은 사람들이 똑같거나 유사한 문제에 이미 부딪혀 봤을 것이기 때문에, 문제들의 패턴을 모아둔 해결책이 필요했습니다.
위 아이디어를 통해, 'Gang of 4; GoF' 23개의 디자인 패턴들을 시작으로 지금까지 다양한 패턴들이 등장했습니다.
GoF 23 Patterns
프로젝트 설계에서 자주 나오는 문제 상황에 대해 검증된 해결 방법 (패턴)을 정리해 놓은 것입니다.
분류 범위와 목적에 따라, Scope (클래스와 오브젝트) 와 Purpose 로 분류된 건 아래 표와 같습니다.

객체 (Creational) 패턴
객체 생성 방식에 유연성을 부여하여, 코드의 의존성을 줄이는 데 초점을 둡니다.
| Factory Method | 객체 생성을 하위 클래스에다가 위임 |
| Abstract Factory | 관련 객체들을 생성하는 Interface 제공 |
| Builder | 복잡한 객체의 생성 과정을 분리, 단계별로 |
| Prototype | 기존의 객체를 clone(복제)해 새로운 객체 생성 |
| Singleton | 오직 하나의 인스턴스 생성만 보장 |
구조 (Structural) 패턴
클래스나 객체를 조합해 더 큰 구조를 만드는데 초점을 둡니다.
| Adaptor | 인터페이스 호환이 되지 않는 클래스들을 연결 |
| Bridge | 구현부에서 추상층을 분리해 독립적으로 확장 |
| Composite | 객체들을 트리 구조로 구성해 부분-전체 계층으로 표현 |
| Decorator | 객체에 새로운 책임(기능)을 동적으로 추가 |
| Facade | 복잡한 sub-시스템을 단순화한 interface를 제공 |
| Flyweight | 공유를 통해 메모리 최소화 |
| Proxy | 접근 제어, Logging 등을 위한 대리 객체 사용 |
행위 (Behavioral) 패턴
객체 간의 책임 분산과 Communication에 초점을 둡니다.
| Interpreter | 언어의 문법을 클래스로 해석, 표현 |
| Template Method | 알고리즘의 구조는 고정하고, 세부는 하위 클래스에다가 위임 |
| Chain of Responsibility | 요청을 처리할 수 있는 객체가 (chain을 따라 연쇄적으로) chain 상에 위치 |
| Command | 명령을 객체로 캡슐화, Undo/Redo 기능 제공 |
| Iterator | 컬렉션 내부 구조 노출 없이 순회 |
| Mediator | 객체 간 상호작용을 중재자 객체로 처리 |
| Memento | 객체의 특정 상태로 돌아갈 수 있도록 상태를 실체화 |
| Observer | 한 객체의 상태 변화시, 관련 객체에게 알림 |
| State | 상태에 따라 행동을 바꿈 |
| Strategy | 알고리즘을 캡슐화해 자유롭게 교체 가능 |
| Visitor | 객체의 구조를 변경하지 않고 새로운 동작 추가 (수행할 연산을 분리해 별도의 클래스로 구성) |
예시 상황
게임 개발에서의 예시로 한번 떠올려 보겠습니다. (주관적인 정리라, 정확하지 않을 수도 있어요!)
Singleton
전체 프로그램에서 오직 하나의 인스턴스만 존재하도록 보장
- GameManager, AudioManager 등에서 글로발하게 접근이 필요한 경우
public class GameManager : MonoBehaviour {
// 전역에서 접근 가능한 인스턴스
public static GameManager Instance { get; private set; }
void Awake() {
// 이미 인스턴스가 존재한다면, 자기자신 제거 (중복 방지)
if (Instance != null && Instance != this) {
Destroy(gameObject);
return;
}
// 인스턴스 설정
Instance = this;
// Scene이 변경돼도 지우지마쇼
DontDestroyOnLoad(gameObject);
}
}
Factory Method
객체 생성 코드를 sub클래스에 위임, 객체 생성을 캡슐화
- 다양한 타입의 적 캐릭터나, 무기, 아이템 등을 조건에 따라 생성
// Enemy 추상 클래스, 적들의 부모 클래스 (공통적으로 상속할 거)
public abstract class Enemy {
public abstract void Attack(); // 각각의 적마다 다른 공격 방식
}
// Zombie 클래스, Enemy를 상속 받음
public class Zombie : Enemy {
public override void Attack() {
Debug.Log("Zombie Bites!"); // Zombie 만의 공격 방식 (추상클래스 Override 참고해주셔용)
}
}
// EnemyFactory, 적을 생성하는 팩토리 (마크의 몹 생성기처럼)
public class EnemyFactory {
// 타입에 따라 적 객체를 생성해 반환
public Enemy CreateEnemy(string type) {
if (type == "Zombie")
return new Zombie(); // "Zombie"일 경우 좀비 생성
return null; // 알 수 없는 타입이면 null 반환
}
}
Observer
객체의 상태가 변할 때, 의존(성이 있는) 객체들에게 자동으로 알림 (관찰자패턴)
- Event system, UI 갱신이나 이것 저것 상태 변화 등 전파 매개가 필요할 때
public class Subject {
// 이벤트 선언, subscriber가 등록될 수 있음
public event Action OnSomethingHappened;
// 어떤 일이 발생했을 때 호출
public void DoSomething() {
Debug.Log("Something happened!");
// subscriber들에게 알림 보내기, (null 체크)
OnSomethingHappened?.Invoke();
}
}
// ex) subject.OnSomethingHappened += SomeMethod; // subscriber가 이벤트에 등록
Strategy
알고리즘을 (행동을) 인터페이스로 분리하고, 런타임에도 교체 가능토록 설계
- AI 패턴, 이동 방식 변경이나, 공격 패턴 전략 등등 선택할 때
// strategy 인터페이스, 이동 방식 정의
public interface IMoveStrategy {
void Move(); // 전략 메서드
}
// 걷기
public class WalkStrategy : IMoveStrategy {
public void Move()
{
Debug.Log("Walking");
}
}
// 달리기
public class RunStrategy : IMoveStrategy {
public void Move() {
Debug.Log("Running");
}
}
// 위의 strategy를 주입받아 사용되는 Player Class
public class Player {
private IMoveStrategy strategy; // 현재 strategy
// strategy 설정
public void SetStrategy(IMoveStrategy s) {
strategy = s;
}
// strategy에 따른 이동
public void Move() {
strategy.Move(); // 현재 설정된 strategy 실행
}
}
Command
요청을 객체로 캡슐화, 실행/취소/저장 등을 구현
- Undo나, 입력 키 Queue, UI 버튼 시스템에서
// Command 인터페이스
public interface ICommand {
void Execute(); // 실행
void Undo(); // 취소
}
// 점프 Command
public class JumpCommand : ICommand {
public void Execute() {
Debug.Log("Jump"); // 점프 실행
}
public void Undo() {
Debug.Log("Undo Jump"); // 점프 취소
}
}
// Command 실행 예시
// var cmd = new JumpCommand();
// cmd.Execute();
// cmd.Undo();
State
객체의 상태에 따라 행동에 변화를 주도록 구성
- 플레이어 상태 (애니메이션이나 다른 용도로 필요한 Idle, Run, Attack 등), 적 공격 패턴 등
// state 인터페이스
public interface IState {
void Handle(); // 상태별 행동
}
// 대기 state
public class IdleState : IState {
public void Handle() {
Debug.Log("Idle..."); // 대기 중
}
}
// 달리기 state
public class RunState : IState {
public void Handle() {
Debug.Log("Running..."); // 달리는 중
}
}
// 캐릭터 클래스, state에 따라 행동
public class Character {
private IState state; // 현재 state
// state 설정
public void SetState(IState s) {
state = s;
}
// state 기반 처리
public void Update() {
state.Handle(); // 현재 state의 행동 실행
}
}
Decorator
기존 객체에 동적으로 기능을 덧붙임
- 아이템 효과 부여, 능력 강화, 인챈티드 템 같은 거
// 무기 인터페이스
public interface IWeapon {
void Attack(); // 공격 메서드
}
// 기본 검
public class Sword : IWeapon {
public void Attack() {
Debug.Log("sword Attack"); // 기본 공격
}
}
// 불 속성 부여 데코레이터
public class FireDecorator : IWeapon {
private IWeapon baseWeapon; // 원본 무기 참조
public FireDecorator(IWeapon weapon) {
baseWeapon = weapon; // 주입
}
public void Attack() {
baseWeapon.Attack(); // 원래 무기 공격
Debug.Log("Fire Enchant"); // 불 속성 효과 추가
}
}
// 사용 예시
// IWeapon sword = new Sword();
// IWeapon fireSword = new FireDecorator(sword);
// fireSword.Attack();
Facade
복잡한 sub-시스템을 간단한 Interface로 구성
- 서브시스템 초기화, API 간편화
// 게임 시작을 간단하게 처리하는 facade 클래스
public class GameSystemFacade {
public void StartGame() {
// 각 서브 시스템들 초기화
AudioManager.Instance.Init(); // 오디오 초기화
SaveManager.Instance.Load(); // 저장된 데이터 로드
UIManager.Instance.ShowStartUI(); // UI 표시
}
}
Builder
복잡한 객체를 단계별로 구성할 수 있도록 분리하고 싶을때 사용
- 몹 생성기, UI 창 구성이나 복잡한 옵션에서 선택할 때
// 캐릭터 클래스, 설정할 속성들
public class Character {
public string Name;
public int HP;
public int MP;
}
// 캐릭터 생성 빌더
public class CharacterBuilder {
private Character character = new Character(); // 빌더 내부 객체
// 이름 설정
public CharacterBuilder SetName(string name) {
character.Name = name;
return this; // 체이닝 가능
}
// HP 설정
public CharacterBuilder SetHP(int hp) {
character.HP = hp;
return this;
}
// MP 설정
public CharacterBuilder SetMP(int mp) {
character.MP = mp;
return this;
}
// 최종 객체 반환
public Character Build() {
return character;
}
}
///<summary>
/// 사용 예시
/// var warrior = new CharacterBuilder()
/// .SetName("Warrior")
/// .SetHP(200)
/// .SetMP(50)
/// .Build();
///</summary>
너무 많네용 ᐡ´•﹃•`ᐡ
모두들 화이팅하시고,
오늘도 좋은 하루 되시길 바랍니다~ ( ⸝⸝•ᴗ•⸝⸝ )੭⁾⁾
'- CS > OOP' 카테고리의 다른 글
| [CS] DI Dependency Injection (2) | 2025.06.23 |
|---|---|
| [OOP] OOP Object-Oriented Programming 개요 (1) | 2025.06.07 |
| [OOP] SOLID 설계 원칙 (2) | 2025.06.07 |