이전 글에 책임패턴의 세 가지 패턴에 대해 다루었다. 이번 포스트에서는 아래 세 패턴에 대해 다룰 것이다.
- 프록시 패턴 : 하나의 객체가 다른 객체를 대신하게 함
- 책임 체인 패턴 : 요청을 보내느느 쪽과 받는 쪽의 결합을 피함
- 플라이웨이트 패턴 : 본질적인 것과 부가적인 것을 구분함
일반적으로 객체는 자신의 데이터 및 자신의 동작에만 책임을 가진다. 그러나, 그렇지 않은 경우가 존재한다.
1. 책임을 중앙집중화
2. 요청을 위임 또는 확대
3. 다른 객체 대신에 동작하게 함 -> 대표적으로 프록시 패턴
4. 객체로부터 다른 객체로 의존하게 하는 책임을 최소화이 네가지 경우에는 다른 객체의 동작에 책임을 가질 수 있다. 그 경우에 대해 논하여 볼 것이다.
Proxy란, 대리(행위)나 대리권, 대리 투표, 대리인의 뜻을 갖는다.
무거운 객체 생성을 해당 객체가 필요할 때까지 미루고 싶을 때
특정 객체에 대한 접근(access)을 조절하기 위해 대리자를 두고 싶을 때
Surrogate라고도 함
특정 객체에 접근을 조절하기 위해 대리자(프록시)를 세운다.(대리자(Proxy, Agent) 내세우기)
필요할 때만 비싼 대가의 기능을 접근하도록 프록시를 사이에 둔 것이다.
즉, 시간이 많이 소요되는 불필요한 복잡한 객체를 생성하는 시간을 간단한 객체로 줄일 수 있다.
프록시는 클라이언트의 요청을 RealSubject 객체에게 보낸다.
프록시 목적에 따라 여러 종류가 있다
문맥에 민감한 도움말 시스템에서, GUI 환경에서 사용자의 현재 위치/상태에 따라 적절한 도움말을 제시하고자 한다. 이때, 책임 체인 패턴을 사용하여 현재 GUI 객체가 도움말을 가지고 있다면 이를 보여주고, 없다면 자신을 포함하고 있는 상위 GUI 객체에게 도움말 처리를 요청할 수 있다.
책임을 분산시켜서 결합력을 약하게 하는 패턴
<책임을 가진 클래스들의 연속>
객체들의 연결고리(chain)을 만들어, 요청에 대해 각 객체는 자신이 처리할 수 있으면 자신이 처리하고, 그렇지 않다면 연결된 다음 객체에게 요청을 넘긴다.(the chain of responsibility)
특정 요청에 대해 이를 처리하는 객체를 고정하지 않는다.
요청을 보내는 객체(sender)와 요청을 처리하는 객체(receiver)를 분리한다.
필수요소: 시퀀스다이어그램 안에서 책임을 가진 클래스들이 '연결'되있어야 함
결합도를 줄인다. 따라서 요청을 보내는 객체는 어떤 객체가 해당 요청을 처리할 지 몰라도 되며, 요청을 처리할 수 있는 복수 개의 객체들에 대한 reference를 모두 가질 필요가 없다. 첫번째 객체에게 요청을 보내면, 다음 연결고리에 있는 객체들이 자동으로 요청을 전파한다.
두 번째로는 객체에 책임 배정이 융통적이다. 연결고리에 객체들을 동적으로 삽입하고, 삭제할 수 있으며 객체들 간의 책임 분산에 동적으로 이루어진다.
단점으로는, 처리가 되었는지 확신하지 못한다. 연결고리에 있는 객체들 모두가 특정 요청을 처리할 수 없는 경우엔 sender는 요청이 처리되었는지 확신할 수 없다는 것이다.
수많은 작은 객체를 생성해야할 때 = 응용 프로그램이 많은 객체를 필요로 할 때
사용되는 많은 객체의 생성 관리하는 객체를 따로 둬 이를 통해 필요한 객체를 참조형태로 사용하도록 한다
본질적인 것과 부가적인 것을 구분하려할 때
많은 객체의 사용으로 저장 공간에 대한 부담이 클 때
Extrinsic state를 제외하면, 대부분의 객체들이 상대적으로 소수의 공유 객체로 대체될 수 있을 때
응용 프로그램이 객체들을 서로 구분할 필요가 없을 때
데이터를 많이 가지고 있는 것들 中 본질적인 것과 비본질적인 것(부가적인 것)을 나누려 할 때
ex 게임 캐릭터를 많이 생성해야함. 근데, 같은 캐릭터에서는 같이 공유하는 부분이 있음.-> 무거운 것을 덜어내는 패턴
각 객체가 가지는 정보들 중 공유될 수 있는 정보들이 있다. 공유할 수 있는 것은 최대한 공유하여 메모리를 최소화하자는 개념이다.
공유할 수 있는 정보를 외부 객체로 만들고 이를 공유한다.
실제 공유가 이뤄지기 위해 각 CharacterShare Subclass들의 객체가 하나씩만 생성됨을 보장해야하는데, 이를 관리하기 위하여 첫번째로 싱글톤 패턴을 사용하는 방법이 있다. 각 캐릭터 객체는 자신에게 맞는 캐릭터 공유 객체를 싱글톤 객체로 구현한다.
두 번째 방법으로는, 팩토리를 사용하는 것이다. CharacterShare Subclass 객체를 생성하는 팩토리 클래스를 작성해, 각 캐릭터 객체는 자신에게 맞는 CharacterShare 객체 생성을 팩토리에게 요청하는 방법이다. 즉, 팩토리는 각 CharacterShare Subclass마다 단 하나의 객체만 생성되도록 보장한다.