디자인 패턴이란?
- 디자인 패턴은 개발하면서 발생하는 반복적인 문제들을 어떻게 해결할 것인지에 대한 해결 방안으로 실제 현업에서 비즈니스 요구 사항을 프로그래밍으로 처리하면서 만들어진 다양한 해결책 중에서 많은 사람들이 인정한 모범 사례이다.
- 디자인 패턴은 객체 지향 4대 특성(캡슐화, 상속, 추상화, 다형성)과 설계 원칙(SOLID)을 기반으로 구현되어 있다.
디자인 패턴의 장점
1. 재사용성 : 반복적인 문제에 대한 일반적인 해결책을 제공하므로, 이를 재사용하여 유사한 상황에서 코드를 더 쉽게 작성할 수 있다.
2. 가독성 : 일정한 구조로 정리하고 명확하게 작성하여 개발자가 코드를 이해하고 유지보수하기 쉽게 만든다.
3. 유지보수성 : 코드를 쉽게 모듈화할 수 있으며, 변경이 필요한 경우 해당 모듈만 수정하여 유지보수가 쉬워진다.
4. 확장성 : 새로운 기능을 추가하거나 변경할 때 디자인 패턴을 활용하여 기존 코드를 변경하지 않고도 새로운 기능을 통합할 수 있다.
5. 안정성과 신뢰성 : 수많은 사람들이 인정한 모범 사례로 검증된 솔루션을 제공한다.
디자인 패턴의 종류
어댑터 패턴(Adapter Pattern)
- 인터페이스를 클라이언트에 맞춰주는 패턴으로, 서로 다른 객체들이 같은 형식(인터페이스) 아래 작동할 수 있도록 하는 것이다.
- 인터페이스 호환성을 제공하지 않는 클래스를 사용하기 위해 래퍼(wrapper) 함수를 이용하는 것이라고 볼 수 있다.
퍼사드 패턴(Facade Pattern)
- 객체 그룹에 간단하지만 구체적인 인터페이스를 제공하는 경우에 많이 사용한다.
- 한 작업에서 여러 클래스를 생성하여 복잡한 작업을 해야할 때, 이 과정들을 외벽 뒤로 숨겨 추상화할 때 사용한다.
장점
- 복잡한 시스템으로부터 간단한 인터페이스를 만들 수 있다.
- 인터페이스의 분리를 통해 클라이언트와 실제 역할을 하는 클래스 간 결합도를 낮출 수 있다.
단점
- 퍼사드 클래스가 지나치게 비대해질 경우 유지보수가 좋지 않다.
- 사용자에게 하위 클래스(일을 하는 클래스)를 완전히 숨길 수 없다.
ex) 퍼사드가 물건 구매 인터페이스를 가진다고 했을 때, 사용자는 단순히 물건 구매 인터페이스를 호출하기만 하면, 파사드 패턴 안에서 하위 클래스(창고에서 물건 꺼내오기, 송장번호 붙이기, 택배 보내기 등)들을 조합해서 사용자가 알 수 없게 일을 잘 처리하는 과정을 거치게 된다.
널 오브젝트 패턴(Null Object Pattern)
- 객체를 활용하는 경우, 어디에서 객체를 구해오면 해당 객체가 null인지 아닌지를 확인해야 하는데 이 경우 코드가 보기 싫어지게 된다.
때문에 이 경우에 객체를 반환하는 함수에서 null을 반환하는 것이 아닌, null과 의미가 유사한 널 오브젝트를 반환하는 것이다.
반환되는 널 오브젝트는 실제로 null이 아닌 객체지만, 하는 일이 없는 객체를 의미한다.(필자는 red-black tree의 nil 노드와 비슷하다고 느꼈다.)
- null 오브젝트를 활용하면 null을 처리하는 코드를 줄일 수가 있다.
옵저버 패턴(Observer Pattern)
- 옵저버 패턴은 객체 간의 일대다 종속 관계를 정의하여 한 객체의 상태 변경이 다른 객체들에게 알려지도록 하는 패턴이다.
즉, 객체의 상태 변화를 관찰하는 옵저버들(객체)을 두어 변화가 있을 때마다 객체가 옵저버들에게 메소드 등으로 통지하는 패턴이다.
변화가 있는 객체에서 옵저버 리스트를 두어 변화가 있을 때 리스트에 있는 옵저버들을 호출하게 된다.
장점
- 객체와 옵저버 간 결합이 느슨해진다.
- 직관적인 이해가 쉽다.
단점
- 멀티 스레드 환경에서 등록/취소 작업과 실행 작업이 겹칠 수 있어 결과가 비틀어질 수 있다.
- 너무 많은 옵저버가 있는 경우 시간이 느려지기도 하고 상태 관리가 힘들다.
프록시 패턴(Proxy Pattern)
- 프록시는 클래스를 이어주는 대리인 역할을 하는 클래스이다. 이를 활용한 것이 프록시 패턴이다.(필자는 클라이언트-서버에서 프록시의 역할과 같다고 생각한다.)
장점
- 실제 일을 하는 클래스와 구분 지을 수 있다.
- 사이즈가 큰 객체가 있을 시 로딩 전에 프록시 객체를 통해 참조 가능하다.(접근 제어, 지연 로딩)
단점
- 로직이 복잡해지면서 코드 읽기가 좋지 않을 수 있다. 때문에 가급적 다른 해결법을 찾는 것이 좋다.
- 객체 생성 시 단계가 늘어나게 된다. 이로 인해서 빈번한 생성, 삭제에서는 메모리가 무거워진다.
싱글톤 패턴(Singleton Pattern)
- 클래스의 인스턴스를 한 개만 가지게 하는 디자인 패턴이다.
싱글톤 패턴의 사용 이유, 장점
- 싱글톤 패턴을 활용한 클래스의 생명주기가 프로그램의 생명주기와 같게 된다. 프로그램이 메모리에 올라감과 동시에 함께 올라가고, 프로그램이 종료될 때 사라지게 된다.
이런 점을 이용하여 메모리에 한 번만 올라간다는 특징 덕분에 여러 인스턴스의 생성을 통한 메모리 사용을 막을 수 있다.
- 전역으로 메모리에 올라가기에 다른 인스턴스들에서도 자유롭게 접근이 가능하다.
싱글톤 패턴의 단점
- 계속 메모리에 올라가 있기 때문에 사용하지 않을 때도 메모리를 점유한다.
- 소멸에 대한 부분이 정의되지 않기 때문에 C++ 환경에서 사용할 때 소멸된 객체에 대한 역참조 문제가 있을 수도 있다.
- 싱글톤 인스턴스가 null인지 항상 체크하게 되는 비효율성이 있을 수 있다.
- 동시성 문제가 있다.
멀티 스레드 환경에서 인스턴스가2개 생기는 경우도 있고, 여러 스레드에서 참조할 때 동기화 처리를 해줘야 하는 번거로움이 있다. 이로 인해 버그 탐색도 어려워지게 된다.
전략 패턴(Strategy Pattern)
- 알고리즘을 정의하고, 실행 중에 선택할 수 있도록 하는 패턴이다.
인터페이스를 통해 특정 행동들을 인터페이스로 묶고, 이를 교환하면서 사용하는 패턴이다.
ex) 게임을 예시로, 캐릭터의 무기가 총, 칼이 있다고 하면 다음과 같이 전략 패턴을 활용할 수 있다.
// IWeapon.h
class IWeapon
{
public:
virtual void Attack() = 0;
};
// Player.h
class Player
{
IWeapon* Weapon;
//... 만약 공격 키가 눌리면
Weapon->Attack();
};
class Sword : public Weapon
{
virtual void Attack() override
{
//.. 검을 휘두른다
}
};
class Gun : public Weapon
{
virtual void Attack() override
{
//.. 총을 쏜다
}
};
플레이어가 무기를 변경한다고 해도 무기들의 Iweapon 정의만 알고 있다면 플레이어의 코드 변경 없이 교체가 가능해진다.
즉, 구체적인 클래스와 알고리즘 사이의 결합도를 낮추는 디자인 패턴으로 구체 클래스를 수정하는 일이 줄어드는, 유지보수에 도움이 되는 디자인 패턴이다.
스테이트 패턴(State Pattern)
- 객체의 상태를 캡슐화하고, 상태 전환을 관리한다.
- 한 번에 한 상태만 가질 수 있는 FSM(Finite State Machine)을 제작할 때 많이 사용하는 패턴으로, 중첩 switch / case 문으로 구현할 수 있지만, 상태가 많아질수록 확장성이 떨어지기 때문에 스테이트 패턴을 이용하여 구현할 수 있다.
상위 인터페이스인 State에서는 관련 기능들에 대한 함수들을 준비하고, 상속받는 파생 State들에서는 해당 State에서 할 수 있는 함수를 구현하는 방식이다.
전략 패턴과의 차이
- 스테이트 패턴은 전략 패턴과 비슷한 모습을 하고 있다. 스테이트 패턴은 조건문을 대체하는 것이고, 전략 패턴은 상속을 대체할 수 있도록 나온 것이기 때문이다.
- 스테이트 패턴에서는 State들의 파생 클래스들이 일을 하는 Context 클래스에 대한 참조를 가지고 있다는 차이를 가지고 있다.(전략 패턴은 이런 경우가 없다.)
- 스테이트 패턴은 전략 패턴이 될 수 있지만, 전략 패턴은 전부 스테이트가 될 수는 없다.
ex) 위의 경우, Zombie의 State를 캡슐화하여, 파생 State들을 두어 관리하는 것을 볼 수 있다.
reference
'OOP(객체 지향 프로그래밍)' 카테고리의 다른 글
[OOP] 객체 지향 언어의 특징 4가지(캡슐화, 상속, 추상화, 다형성) (0) | 2024.11.11 |
---|---|
[OOP] 객체 지향 설계의 5가지 원칙(SOLID) (0) | 2024.06.13 |