[design pattern] # 09. 책임패턴2 - 프록시, 책임체인, 플라이웨이트

zio·2023년 1월 17일
0

Design Pattern

목록 보기
1/1

객체지향 설계와 패턴 Lecture #8. 책임 패턴 2

  • Proxy Pattern - 하나의 객체가 다른 객체를 대신하게 함
  • Chain of Responsibility Pattern - 요청을 보내는 쪽과 받는 쪽의 결합을 피함
  • Flyweight Pattern - 본질적인 것과 부가적인 것을 구분함

프록시 패턴


  • 요약

    • 특정 객체에 접근(access)을 조절하기 위하여 대리자(프록시)를 세움
    • 필요할 때만 비싼 대가의 기능을 접근하도록 프록시를 사이에 둠
    • 보이지 않는 부분을 proxy로 갖고있다가 나중에 보여질 때 원본을 가져옴
  • 역할

    • 시간이 많이 소요되는 불필요한 복잡한 객체를 생성하는 시간을 간단한 객체로 줄임
    • ex) 웹 페이지 - 실제 화면에 출력할 필요가 있는 객체만 생성하고 밑에 있는 것들은 proxy로 갖고있다가 active되면 original을 가져옴 → 처음부터 original을 가져오면 웹 페이지를 처음 가져올 때 시간이 너무 오래 걸림 → 비요휼적임
  • 기존 설계(예제: 문서편집기)

  • Proxy Pattern 적용한 설계(예제: 문서편집기)

    • 대리자(proxy)로 original객체를 대신하고 proxy는 요청을 받았을 때 original 객체를 가져옴 → 효율적 운영
    • proxy가 original의 요청을 받으면 original이 있는지 확인해서 있으면 바로 주고 없으면 original을 불러옴
    • 따라서 proxy는 original의 위치를 알고있어야 함
    • 클래스 다이어그램
  • 구조 및 구성요소

    • 일반적인 구조 → Client가 proxy / original 에 대해 같은 인터페이스로 이용할 수 있도록
    • 구성 요소 → Proxy[대리자]: Subject인터페이스를 구현하여 RealSubject객체를 대신할 수 있음. RealSubject객체에 대한 레퍼런스 유지 및 접근 조절, 해당 객체의 생성과 소멸을 책임 질 수도 있음. → Subject[인터페이스]: RealSubject와 Proxy의 공통 인터페이스 → RealSubject[실제객체]: Proxy가 대신할 original객체
    • 프록시는 클라이언트의 요청을 RealSubject 객체에 보냄 → association
  • 프록시 종류

    • 리모트 프록시: 다른 공간에 존재하는 객체에 대한 로컬 표현 (disk→screen)
    • 가상 프록시: 복잡한 객체를 필요할 때 생성 (ex. game)
    • 보호(protection) 프록시: 원래 객체에 대한 접근 권한을 제한 (ex.인증 과정 거쳐서 접근)
    • 스마트 레퍼런스: 객체 접근시 추가적인 액션 수행, 객체의 참조 회수 관리 or 객체를 수정할 수 없도록 locking
  • 적용 결과

    • 투명성: 리모트 프록시는 객체가 다른 주소공간에 존재하는 사실을 숨길 수 있게 함 → Client입장에서는 차이를 못느낌 but, 시간은 빨라짐
    • 최적화: 가상 프록시는 객체를 필요할 때 생성하여 최적화 수행. 불필요한 다운로드 또는 heavy work 피함
    • 보호 프록시와 스마트 레퍼런스는 객체가 접근할 때 추가적인 housekeeping작업을 수행한다. (ex. 관리를 위해 count, traffic, 가격 계산 등등 추가적인 것들)

책임 체인 패턴


  • 요약

    • 요청을 보내는 객체(sender)와 요청을 처리하는 객체(receiver)를 분리
    • 요청에 대하여 자신이 처리할 수 있으면 요청을 처리하고 처리할 수 없으면 연결된 다음 객체에 요청을 넘긴다.
  • 역할

    • 요청을 보내는 객체와 요청을 처리하는 객체를 분리하여 결합도를 줄여 추가, 수정시 코드 변경 영향을 줄인다.
    • 결합도를 낮춤: 요청을 보내는 쪽은 어떤 객체에 전달할지 고려 안해도 되고 요청을 처리할 수 있는 객체들의 reference를 모두 가질 필요가 없다. 첫번 째 객체에게 요청을 보내면 그 다음부터는 연결고리 객체들이 자동으로 요청을 전파함 → 따라서 결합도를 낮출 수 있음
    • 객체에 책임 배정이 융통적임: 연결고리 객체들을 동적으로 삽입, 삭제할 수 있음 → 수정, 변경 융통적, 객체들 간의 책임 분산이 동적으로 이루어짐
  • 기존 설계(예제: 도움말GUI)
    - 도움말 기능을 전담하는 객체 정의 → coupling이 높음(switch문) → 수정 및 기능 추가시 코드 변경이 많이 됨

    - 장점: 도움말 관련 기능을 한 군데로 모임 → 관리와 기능 확장이 용이
    - 단점: setState()함수를 이용하여 사용자의 현재 상태를 설정 → coupling 높음 → 새로운 상태와 기능이 추가 혹은 변경시 영향받는 범위 커짐.

  • Chain of Responsibility Pattern 적용한 설계(예제: 도움말GUI)

    • 클래스 다이어그램
    • 특정 요청에 대하여 이를 처리하는 객체를 고정하지 않고 요청을 처리하는 객체 group에 이 요청을 보냄
    • 요청을 보내는 객체(sender)와 요청을 처리하는 객체(receiver)를 분리
    • 객체들의 연결 고리(chain) → 요청에 대하여 각 객체는 자신이 처리할 수 있으면 처리 → 처리할 수 없으면 연결된 다음 객체에 요청을 넘김(chain of responsibility)
  • 구조 및 구성요소

    • 클래스 다이어그램

    • 요청 전파를 위해 상속 구조

    • 요청을 처리하지 못한 경우 이 요청을 다음 객체로 전달할 수 있도록 지정되어야함

    • 처리 확신 불가: 연결고리에 있는 객체들 모두가 특정 요청을 처리할 수 없는 경우 있을 수 있음 → sender는 요청 처리를 확신할 수 없음

  • 구현

    • 후속 체인의 구현 → 기존에 존재하는 링크를 이용: 상속 관계로 인한 연결 레퍼런스 존재, 이 링크를 "책임 체인"링크로 사용할 수 있음 → 체인을 구성하기 위한 링크를 새로 정의: 일반적으로 핸들러 클래스에서 구현
    • 다음 처리(successor) 연결 → 링크를 새로 정의하는 경우, 링크에 대한 관리와 호출을 구현해야 함
    • 요청이 하나가 아니고 여러개라면 → 각 요청에 대하여 개별적인 함수 구현 → 요청을 표현하는 객체(Request)를 만들어서 이를 handleRequest()함수의 인자로 넘김

플라이웨이트 패턴


  • 요약

    • 수많은 작은 객체를 생성할 때 사용되는 많은 객체의 생성을 관리하는 객체를 따로 두어 이를 통해 필요한 객체를 참조형태로 사용한다.
    • 본질적인 것과 부가적인 것을 구분하려 할 때 사용
  • 역할

    • 클래스가 데이터를 무겁게 갖고있을 때 공유할 필요가 있는 것과 없는 것을 나누어 공유할 수 있는 것을 분리하여 따로 관리하며 필요할 때 마다 참조해서 사용하도록 한다.
  • 기존 설계(예제: 게임 캐릭터)

    • 클래스다이어그램
  • Flyweight Pattern 적용한 설계(예제: 게임 캐릭터)

    • 클래스다이어그램

      → 공유되는 것과 공유되지 않는 것을 분리하고 링크로 공유 객체를 가져옴

  • 공유객체 관리
    - 싱글톤 패턴 사용하기
    공유 객체는 하나만 있어도 되므로 static으로 선언. 싱글톤 패턴을 사용하여 공유 객체는 하나만 생기도록 한다.

    - 팩토리 사용하기
    공유 서브클래스 객체를 생성하는 팩토리 클래스 생성 → 객체 생성 위임
    각 객체는 자신에 맞는 공유 객체 생성을 팩토리에 요청
    팩토리는 각 공유 서브 클래스마다 단 하나의 객체만 생성되도록 보장

    → 팩토리 패턴을 적용하여 공유 객체 생성을 위임 → 만들어져있는 공유 객체가 있으면 반환하고 없으면 새로 만들어서 반환

  • 구조 및 구성요소

    • 클래스다이어그램
    • Flyweight: 공통 인터페이스. extrinsic data를 넘겨받아 연산 수행.
    • ConcreteFlyweight: 공유될 수 있는 객체들. Flyweight 인터페이스를 구현하고 intrinsic data를 보관
    • UnsharedConcreteFlyweight: 공유하지 않지만 공유되는 객체들과 같이 취급되는 객체들을 표현
    • FlyweightFactory: flyweight객체를 생성하고 관리. 공유를 책임짐. 싱글톤 패턴 적용하여 객체 하나만 만들어지도록(공유 객체의 유일성 보장)
    • Client: (필요하다면) extrinsic data를 보관하거나 계산한다. → Client는 직접적으로 ConcreteFlyweight 객체를 생성하지 않고, FlyweightFactory 객체를 통해 공유객체 생성 → Unshared 객체를 부르고 Unshared 객체가 share 객체 불러서 합침
  • 적용 및 구현

    • 객체의 상태: Intrinsic state, Extrinsic state → Intrinsic state: 공유될 수 있는 상태 정보. ConcreteFlyweight 객체에 보관됨 → Extrinsic state: 공유될 수 없는 상태나 상황(context) 정보. Client에서 보관되거나 계산됨 → Extrinsic state가 차지하는 메모리 공간이 적거나, 저장하지 않고도 간단한 계산을 통해서 얻어질 수 있는 경우라면 객체 공유로 얻을 수 있는 효과가 큼 → Intrinsic state가 클 수록 효과적임
    • 적용 범위 → 공통되는 부분이 많을 때 & 객체간 구별 필요 없을 때 → 많은 객체의 사용으로 저장 공간에 대한 부담이 클 때 → Extrinsic state 제외하면, 대부분의 객체들이 상대적으로 소수의 공유 객체로 대체될 수 있을 때 → 응용 프로그램이 객체들을 서로 구분할 필요가 없을 때

2021 Spring 최은만 교수님 객체지향 패턴 및 설계 수업 필기노트

profile
🐣

0개의 댓글