책임패턴 2

froajnzd·2023년 6월 7일
0

pattern

목록 보기
6/15
post-thumbnail

이전 글에 책임패턴의 세 가지 패턴에 대해 다루었다. 이번 포스트에서는 아래 세 패턴에 대해 다룰 것이다.

  • 프록시 패턴 : 하나의 객체가 다른 객체를 대신하게 함
  • 책임 체인 패턴 : 요청을 보내느느 쪽과 받는 쪽의 결합을 피함
  • 플라이웨이트 패턴 : 본질적인 것과 부가적인 것을 구분함

일반적으로 객체는 자신의 데이터 및 자신의 동작에만 책임을 가진다. 그러나, 그렇지 않은 경우가 존재한다.
1. 책임을 중앙집중화
2. 요청을 위임 또는 확대
3. 다른 객체 대신에 동작하게 함 -> 대표적으로 프록시 패턴
4. 객체로부터 다른 객체로 의존하게 하는 책임을 최소화

이 네가지 경우에는 다른 객체의 동작에 책임을 가질 수 있다. 그 경우에 대해 논하여 볼 것이다.

1. 프록시 패턴

Proxy란, 대리(행위)나 대리권, 대리 투표, 대리인의 뜻을 갖는다.

배경(문제상황-해결방안)

무거운 객체 생성을 해당 객체가 필요할 때까지 미루고 싶을 때
특정 객체에 대한 접근(access)을 조절하기 위해 대리자를 두고 싶을 때

설명

Surrogate라고도 함

특정 객체에 접근을 조절하기 위해 대리자(프록시)를 세운다.(대리자(Proxy, Agent) 내세우기)
필요할 때만 비싼 대가의 기능을 접근하도록 프록시를 사이에 둔 것이다.
즉, 시간이 많이 소요되는 불필요한 복잡한 객체를 생성하는 시간을 간단한 객체로 줄일 수 있다.

특징

요소

  • Proxy(ImageProxy) : RealSubject에 레퍼런스 유지, 접근 조절해 해당 객체의 생성과 소멸 책임 / Subject Interface를 구현해 RealSubject 객체를 대신
  • Subject(Graphic) : RealSubject와 Proxy의 공통 인터페이스
  • RealSubject(Image) : Proxy가 대신할 실제 객체

프록시는 클라이언트의 요청을 RealSubject 객체에게 보낸다.

구조

종류

프록시 목적에 따라 여러 종류가 있다

  • 리모트 프록시 : 다른 공간(주소)에 존재하는 객체에 대한 로컬 표현
  • 가상 프록시 : 복잡한 객체를 필요할 때 생성
  • 보호 프록시 : 원래 객체에 대한 액세스 권한 제한
  • 스마트 레퍼런스 : 객체 접근 시 추가적인 액션 수행 / 참조회수를 관리하거나 객체를 수정할 수 없도록 로킹

장점

  • 투명성(리모트 프록시는 객체가 다른 주소공간에 존재하는 사실을 숨길 수 있게 한다)
  • 최적화(가상 프록시는 객체를 필요할 때 생성해 최적화를 수행한다. 불필요한 다운로드와 heavy work를 피한다)
  • 보호 프록시와 스마트 레퍼런스는 객체가 접근할 때 추가적인 Housekeeping작업을 수행한다

2. 책임 체인 패턴

배경(문제상황-해결방안)

문맥에 민감한 도움말 시스템에서, GUI 환경에서 사용자의 현재 위치/상태에 따라 적절한 도움말을 제시하고자 한다. 이때, 책임 체인 패턴을 사용하여 현재 GUI 객체가 도움말을 가지고 있다면 이를 보여주고, 없다면 자신을 포함하고 있는 상위 GUI 객체에게 도움말 처리를 요청할 수 있다.

설명

책임을 분산시켜서 결합력을 약하게 하는 패턴
<책임을 가진 클래스들의 연속>
객체들의 연결고리(chain)을 만들어, 요청에 대해 각 객체는 자신이 처리할 수 있으면 자신이 처리하고, 그렇지 않다면 연결된 다음 객체에게 요청을 넘긴다.(the chain of responsibility)

특징

특정 요청에 대해 이를 처리하는 객체를 고정하지 않는다.
요청을 보내는 객체(sender)와 요청을 처리하는 객체(receiver)를 분리한다.
필수요소: 시퀀스다이어그램 안에서 책임을 가진 클래스들이 '연결'되있어야 함

구조

장점

결합도를 줄인다. 따라서 요청을 보내는 객체는 어떤 객체가 해당 요청을 처리할 지 몰라도 되며, 요청을 처리할 수 있는 복수 개의 객체들에 대한 reference를 모두 가질 필요가 없다. 첫번째 객체에게 요청을 보내면, 다음 연결고리에 있는 객체들이 자동으로 요청을 전파한다.

두 번째로는 객체에 책임 배정이 융통적이다. 연결고리에 객체들을 동적으로 삽입하고, 삭제할 수 있으며 객체들 간의 책임 분산에 동적으로 이루어진다.

단점

단점으로는, 처리가 되었는지 확신하지 못한다. 연결고리에 있는 객체들 모두가 특정 요청을 처리할 수 없는 경우엔 sender는 요청이 처리되었는지 확신할 수 없다는 것이다.

3. 플라이웨이트 패턴

배경(문제상황-해결방안)

수많은 작은 객체를 생성해야할 때 = 응용 프로그램이 많은 객체를 필요로 할 때
사용되는 많은 객체의 생성 관리하는 객체를 따로 둬 이를 통해 필요한 객체를 참조형태로 사용하도록 한다
본질적인 것과 부가적인 것을 구분하려할 때
많은 객체의 사용으로 저장 공간에 대한 부담이 클 때
Extrinsic state를 제외하면, 대부분의 객체들이 상대적으로 소수의 공유 객체로 대체될 수 있을 때
응용 프로그램이 객체들을 서로 구분할 필요가 없을 때
데이터를 많이 가지고 있는 것들 中 본질적인 것과 비본질적인 것(부가적인 것)을 나누려 할 때

ex 게임 캐릭터를 많이 생성해야함. 근데, 같은 캐릭터에서는 같이 공유하는 부분이 있음.-> 무거운 것을 덜어내는 패턴

설명

각 객체가 가지는 정보들 중 공유될 수 있는 정보들이 있다. 공유할 수 있는 것은 최대한 공유하여 메모리를 최소화하자는 개념이다.
공유할 수 있는 정보를 외부 객체로 만들고 이를 공유한다.

특징

실제 공유가 이뤄지기 위해 각 CharacterShare Subclass들의 객체가 하나씩만 생성됨을 보장해야하는데, 이를 관리하기 위하여 첫번째로 싱글톤 패턴을 사용하는 방법이 있다. 각 캐릭터 객체는 자신에게 맞는 캐릭터 공유 객체를 싱글톤 객체로 구현한다.
두 번째 방법으로는, 팩토리를 사용하는 것이다. CharacterShare Subclass 객체를 생성하는 팩토리 클래스를 작성해, 각 캐릭터 객체는 자신에게 맞는 CharacterShare 객체 생성을 팩토리에게 요청하는 방법이다. 즉, 팩토리는 각 CharacterShare Subclass마다 단 하나의 객체만 생성되도록 보장한다.

요소

  • Flyweight(CharacterShare) : 있다면 extrinsic data(외부데이터)를 넘겨받아 연산 수행
  • ConcreteFlyweight(SoldierShare, TankShare, PlaneShare) : 공유 될수 있는 객체 표현/Flyweight 인터페이스 구현/intrinsic data 보관
  • UnsharedConcreteFlyweight : 공유될수 없지만, 공유되는 객체와 같이 취급되는 객체 표현
  • FlyweightFactory : flyweight 객체 생성, 관리/공유 책임
  • Client : 필요하다면, extrinsic data 보관, 계산

구조

profile
Hi I'm 열쯔엉

0개의 댓글