흔히들 시스템에 하나밖에 존재하지 않는 객체의 생성과 접근을 제어하기 위해 사용된다. 싱글턴이 가지는 가장 큰 책임은 함부로 접근되어서는 안 되는 자원을 보호하는 것이다. 접근을 제어할 필요가 없는 자원을 싱글턴으로 작성하는 것은 쓸데없이 객체 접근에 대한 부하만 높이는 꼴이 된다. 싱글턴은 형태가 특이해도 객체지향의 특성을 모두 가지고 있으므로 상속받아서 자식 싱글턴을 만들 수도 있다. 하지만 싱글턴 클래스 자체의 구현이 이해하기 쉽지 않으므로 보다 쉬운 구현을 할 것을 권장한다.
프로토타입 패턴(Prototype)
객체의 원형을 기반으로 자신과 똑같은 객체를 생성하는 방식이다. 추상 팩토리와의 결합으로도 강력함 힘을 낼 수 있다. 또 객체를 복제할 때 내부 상태(객체의 속성)를 동일하게 복제하기 때문에 현재 객체의 스냅숏(snap-shot)을 찍는데 활용할 수도 있다. new/delete 원칙 역시 Clone() 함수가 객체 생성을 위한 함수임이 분명하므로 다른 모습의 new라고 볼 수 있으므로 헷갈리지 않도록 한다.
어뎁터 패턴(Adapter)
호환성을 가지지 않는 인터페이스를 맞추기 위한 목적으로 사용된다. 안정성이 확보된 코드를 DIY(Do It Yourself) 정신에 입각한답시고 분해하는 순간 힘들게 얻은 안정성은 깨어지고 만다. 현실적으로 팀 개발을 할 때 다른 개발자가 작성한 코드를 내가 수정해서 붙인다면 안정성도 문제가 되지만 코드의 책임 소재가 불분명한 점도 간과할 수 없다. 꼭 어댑터 패턴을 사용하겠다는 생각보다는 문제 영역의 최소화와 안정성을 지키기 위한 마음가짐이 더 중요하다.
옵서버 패턴(Observer)
정보 객체가 변경됐을 때 이 정보 객체를 참조하는 다른 객체들에게 변경사항을 알리어 변경된 정보를 즉각적으로 반영할 수 있는 방법이다. 이때 정보 객체를 소유하는 쪽을 서브젝트(Subject)라고 하며 정보 객체를 참조하는 객체를 옵서버(Observer)라고 부른다. 서브젝트와 옵서버는 1대 n의 관계를 가진다.
이 트레이터 패턴(Iterator)
컬렉션 내부 구현과 탐색 방법을 분리시키는 방법이다. 이터레이터 패턴은 탐색하는 행위를 하나의 책임으로 보고 패턴화 했다는데 의의를 가진다. 이 패턴 구현의 가장 중요한 요소는 커서이다. 커서가 컬렉션의 시작과 끝의 범위 안에서 정확히 동작해야 안전한 구현이 가능하다. 멀티스레드 환경에서는 커서의 범위가 수시로 간섭당할 수 있으므로 탐색 전에 범위의 간섭이 일어나지 않도록 해야 한다.
컴포지트 패턴(Composite)
객체들의 트리로 대변되는 객체들 사이의 소유 구조를 동일한 인터페이스로 다룰 수 있는 방법이다. 개별 객체와 복합 객체를 코드상에서 따로 구분하지 않고 이들의 공통점으로 만들어진 인터페이스를 구성하는 것이 이 패턴의 핵심이다. 개별 객체는 자식을 가지지 않는 복합 구조로 이해하면 보다 쉽게 인터페이스를 구성할 수 있다.
스테이트 패턴(State)
내부적으로 다양한 상태를 가지는 객체는 상태 플래그로 인해 복잡한 분기문을 가진다. 스테이트(State) 패턴은 객체의 서로 다른 내부 상태를 각각의 상태 객체로 클래스 화해서 분기문을 제거한다. 결과적으로 클라이언트 코드로 노출되는 인터페이스는 동일하지만 내부 객체 상태 변화에 따라 객체는 다른 모습으로 동작한다.
스트래티지(Strategy)
알고리즘을 독립적으로 확장시킬 수 있는 방법이다. 동일한 인터페이스로 확장된 알고리즘은 클래스의 멤버 함수로 속해 있을 때보다 더 높은 확장성을 가진다. 스트래티지 패턴을 사용하면 무거운 객체를 상속을 사용하지 않고 확장의 범위를 최소화할 수 있다.
프락시(Proxy)
클라이언트 코드에서 사용을 원하는 객체로의 접근을 제어하기 위한 목적으로 사용된다. 프락시는 내부적으로 자신이 '제어' 하는 객체와 동일한 인터페이스를 클라이언트에게 제공하여 클라이언트가 통신을 원하는 객체와 직접적으로 통신을 하는 것처럼 믿게 만든다. 이때 '제어'에 해당하는 책임을 통신을 원하는 객체나 클라이언트 코드가 가지지 않고 프락시가 가짐으로써 너무 무거운 책임을 가지는 객체가 만들어지지 않도록 한다. 원한다면 유동적으로 프락시 객체를 제거하여 '제어'에 해당되는 기능을 제거할 수 있는 유연함이 있다.
플라이 웨이트(Flyweight)
대량으로 생성되는 객체들 사이의 중복되는 정보를 공유, 메모리적인 효율성을 높이는 방법이다. 중복된 정보를 공유하는 방법은 싱글턴, 팩토리, 자원 풀(Resource Pool)등 여러 방법으로 구현될 수 있다. 하지만 가장 중요한 것은 어떤 정보를 공유시키고 어떤 정보를 부가적인 정보로 따로 가져갈 것인지에 대한 분석을 하는 것이다.
커맨드 패턴(Command)
객체의 행동을 별도의 클래스에 캡슐화해서 행동 객체에 확장성을 부여한다. 각각의 커맨드들은 특정 객체에 의존하지 않도록 만들어지므로 재활용성이 매우 높다. JAVA의 UI 이벤트 처리 모델과 같이 행동의 책임을 분산시키기에 좋은 방법이다. 다만 커맨드가 책임을 다하도록 필요한 객체들에 접근할 수 있는 방법이 마련되어야 한다.
데코레이터 패턴(Decorator)
기본 기능을 하는 객체와 이 객체를 기반으로 동작하는 데코레이터들을 조합하여 기능을 확장하는 방법이다. 데코레이터 패턴은 상속보다 유연한 방법으로 동적으로 기능을 추가/삭제할 수 있고 조합해서 쓸 수 있다는 장점이 있다. JAVA의 I/O 모델은 데코레이터 패턴을 사용한 대표적인 사례이다.
댓글 영역