프록시 패턴

Proxy pattern

컴퓨터 프로그래밍에서 프록시 패턴은 소프트웨어 설계 패턴입니다.프록시는 가장 일반적인 형태로 다른 무언가에 대한 인터페이스로 기능하는 클래스입니다.프록시는 네트워크 연결, 메모리 내의 큰 개체, 파일 또는 비용이 많이 들거나 복제할 수 없는 다른 리소스 등 모든 리소스에 인터페이스할 수 있습니다.즉, 프록시는 클라이언트가 백그라운드에서 실제 서비스 개체에 액세스하기 위해 호출하는 래퍼 또는 에이전트 개체입니다.프록시의 사용은 단순히 실제 객체에 전달하거나 추가 로직을 제공할 수 있습니다.프록시에서는 실제 개체에 대한 작업이 리소스를 많이 사용하는 경우 캐싱하거나 실제 개체에 대한 작업이 호출되기 전에 사전 조건을 확인하는 등 추가 기능을 제공할 수 있습니다.클라이언트의 경우 프록시 오브젝트의 사용은 둘 다 동일한 인터페이스를 구현하기 때문에 실제 오브젝트를 사용하는 것과 비슷합니다.

개요

프록시[1] 설계 패턴은 23개의 잘 알려진 GoF 설계 패턴 중 하나로 유연하고 재사용 가능한 객체 지향 소프트웨어, 즉 구현, 변경, 테스트 및 재사용이 용이한 객체를 설계하기 위해 반복되는 설계 문제를 해결하는 방법을 설명합니다.

프록시 설계 패턴으로 해결할 수 있는 문제는 무엇입니까?[2]

  • 개체에 대한 액세스를 제어해야 합니다.
  • 개체에 액세스할 때 추가 기능을 제공해야 합니다.

예를 들어 중요한 개체에 액세스할 때 클라이언트에 필요한 액세스 권한이 있는지 확인할 수 있어야 합니다.

Proxy 설계 패턴은 어떤 솔루션을 설명합니까?

별도 정의Proxy을 반대하다

  • 를 다른 오브젝트 대신 사용할 수 있습니다(Subject)와
  • 는, 이 서브젝트에의 액세스를 제어하는 추가 기능을 실장하고 있습니다.

이것에 의해, Ethernet을 경유해 작업할 수 있게 됩니다.Proxy오브젝트: 서브젝트에 액세스할 때 추가 기능을 수행합니다.예를 들어, 중요한 개체에 액세스하는 클라이언트의 액세스 권한을 확인합니다.

서브젝트를 대체하기 위해 프록시는 다음 명령어를 구현해야 합니다.Subject인터페이스입니다.클라이언트는 서브젝트와 그 프록시 중 어느 쪽을 사용하는지 알 수 없습니다.

아래 UML 클래스 및 시퀀스 다이어그램을 참조하십시오.

구조.

UML 클래스 및 시퀀스 다이어그램

프록시 설계 패턴의 샘플 UML 클래스 및 시퀀스 다이어그램.[3]

위의 UML 클래스 다이어그램에서는Proxyclass는 다음 명령을 실행합니다.Subject대체로서 기능하도록 인터페이스를 설정합니다.Subject물건들.참조를 유지합니다)realSubject치환된 오브젝트( )로 이동합니다.RealSubject요구를 전송할 수 있도록 합니다( ).realSubject.operation()).

시퀀스 다이어그램은 런타임 상호 작용을 보여 줍니다.Client오브젝트는 를 통해 동작하다Proxy에의 액세스를 제어하는 객체RealSubject물건.이 예에서는Proxy요구를 에 전송하다RealSubject이 명령어는 요청을 수행합니다.

클래스 다이어그램

UML 프록시
LePUS3의 프록시(레전드)

사용 가능한 시나리오

리모트 프록시

분산 객체 통신에서 로컬 객체는 원격 객체(다른 주소 공간에 속하는 객체)를 나타냅니다.로컬 개체는 원격 개체의 프록시이며 로컬 개체에서 메서드를 호출하면 원격 개체에서 메서드가 호출됩니다.예를 들어 ATM 실장에서는 리모트서버에 존재하는 뱅크 정보의 프록시 오브젝트가 보관 유지되는 경우가 있습니다.

가상 프록시

복잡하거나 무거운 물체 대신 스켈레톤 표현이 경우에 따라서는 유리할 수 있습니다.기본 이미지의 크기가 클 경우 가상 프록시 개체를 사용하여 실제 개체를 필요에 따라 로드할 수 있습니다.

보호 프록시

보호 프록시는 액세스 권한에 따라 리소스에 대한 액세스를 제어하는 데 사용될 수 있습니다.

C#

인터페이스 ICar {     무효 드라이브카() ; }  // 실제 객체 일반의 학급  : ICar {     일반의 무효 드라이브카()     {         콘솔.기입선("차가 운행되었습니다!");     } }  // 프록시 오브젝트 일반의 학급 프록시카 : ICar {     사적인 드라이버 드라이버;     사적인 ICar 리얼카;      일반의 프록시카(드라이버 드라이버)     {         이것..드라이버 = 드라이버;         이것..리얼카 = 신규 ();     }      일반의 무효 드라이브카()     {         한다면 (드라이버.나이 < > 16)             콘솔.기입선("죄송합니다, 운전자는 운전하기에 너무 어립니다.");         또 다른             이것..리얼카.드라이브카();      } }  일반의 학급 드라이버 {     일반의 인트 나이 { 얻다; 세트; }      일반의 드라이버(인트 나이)     {         이것..나이 = 나이;     } }  // 위의 프록시 클래스 사용 방법 사적인 무효 btnProxy_클릭(물건 송신자, 이벤트 어그 e) {     ICar  = 신규 프록시카(신규 드라이버(15));     .드라이브카();       = 신규 프록시카(신규 드라이버(25));     .드라이브카(); } 

산출량

미안해요, 운전하기엔 너무 어려요.차가 운행되었습니다! 

주의:

  • 프록시는 클라이언트에 대해 실제 개체에 대한 정보를 숨길 수 있습니다.
  • 프록시는 온 디맨드로드와 같은 최적화를 실행할 수 있습니다.
  • 대리인은 감사 업무와 같은 추가적인 하우스 키핑 작업을 수행할 수 있습니다.
  • 프록시 설계 패턴은 대리 설계 패턴이라고도 합니다.

C++

#실패하다 <iostream> #실패하다 <메모리>  학급 ICar {  일반의:   가상 ~ICar() { 표준::외치다 << > "ICAR 파괴자!" << > 표준::; }    가상 무효 드라이브카() = 0; };  학급  : 일반의 ICar {  일반의:   무효 드라이브카() 덮어쓰다 { 표준::외치다 << > "차가 운행되었습니다!" << > 표준::; } };  학급 프록시카 : 일반의 ICar {  일반의:   프록시카(인트 드라이버_에이지) : 드라이버_age_(드라이버_에이지) {}    무효 드라이브카() 덮어쓰다 {     한다면 (드라이버_age_ > 16) {       리얼_카_->드라이브카();     } 또 다른 {       표준::외치다 << > "죄송합니다, 운전자는 운전하기에 너무 어립니다." << > 표준::;     }   }   사적인:   표준::unique_ptr< >ICar> 리얼_카_ = 표준::make_filengths< >>();   인트 드라이버_age_; };  인트 주된() {   표준::unique_ptr< >ICar>  = 표준::make_filengths< >프록시카>(16);   ->드라이브카();     = 표준::make_filengths< >프록시카>(25);   ->드라이브카(); } 

크리스탈

추상적인 학급 추상 자동차   추상적인 방어하다 운전해. 끝.  학급  < > 추상 자동차   방어하다 운전해.     놓다 "차가 운행되었습니다!"   끝. 끝.  학급 드라이버   취득하다 나이 : Int32    방어하다 초기화하다(@age)   끝. 끝.  학급 프록시카 < > 추상 자동차   사적인 취득하다 드라이버 : 드라이버   사적인 취득하다 리얼카 : 추상 자동차    방어하다 초기화하다(@드라이버)     @real_car = .신규   끝.    방어하다 운전해.     한다면 드라이버.나이 <=> 16       놓다 "죄송합니다, 운전자는 운전하기에 너무 어립니다."     또 다른       @real_car.운전해.     끝.   끝. 끝.  # 프로그램 드라이버 = 드라이버.신규(16)  = 프록시카.신규(드라이버) .운전해.  드라이버 = 드라이버.신규(25)  = 프록시카.신규(드라이버) .운전해. 

산출량

미안해요, 운전하기엔 너무 어려요.차가 운행되었습니다! 

델파이 / 오브젝트 파스칼

// 프록시 설계 패턴 구성 단위 디자인 패턴.프록시;  인터페이스  유형     // 차량 인터페이스     ICar = 인터페이스       절차. 드라이브카;     끝.;      // TCar 클래스, ICar 구현     TCar = 학급(TInterfaced Object(TInterfaced Object), ICar)       학급 기능. 신규: ICar;       절차. 드라이브카;     끝.;      // 드라이버 인터페이스     아이드리버 = 인터페이스       기능. 나이: 정수;     끝.;      // TDriver 클래스, IDriver 구현     TDriver = 학급(TInterfaced Object(TInterfaced Object), 아이드리버)     사적인       FAge: 정수;     일반의       컨스트럭터 만들다(나이: 정수); 과부하;       학급 기능. 신규(나이: 정수): 아이드리버;       기능. 나이: 정수;     끝.;      // 프록시 오브젝트     TPoxyCar = 학급(TInterfaced Object(TInterfaced Object), ICar)     사적인       FDriver: 아이드리버;       프릴카: ICar;     일반의       컨스트럭터 만들다(드라이버: 아이드리버); 과부하;       학급 기능. 신규(드라이버: 아이드리버): ICar;       절차. 드라이브카;     끝.;  실행  { TCAR 구현 }  학급 기능. TCar.신규: ICar; 시작한다.      결과 := 만들다; 끝.;  절차. TCar.드라이브카; 시작한다.      기입('차가 운행되었습니다!'); 끝.;  { TDriver 구현 }  컨스트럭터 TDriver.만들다(나이: 정수); 시작한다.      상속된 만들다;      FAge := 나이; 끝.;  학급 기능. TDriver.신규(나이: 정수): 아이드리버; 시작한다.      결과 := 만들다(나이); 끝.;  기능. TDriver.나이: 정수; 시작한다.      결과 := FAge; 끝.;  { TProxyCar 구현 }  컨스트럭터 TPoxyCar.만들다(드라이버: 아이드리버); 시작한다.      상속된 만들다;      자신.FDriver  := 드라이버;      자신.프릴카 := TCar.만들다 ~하듯이 ICar; 끝.;  학급 기능. TPoxyCar.신규(드라이버: 아이드리버): ICar; 시작한다.      결과 := 만들다(드라이버); 끝.;  절차. TPoxyCar.드라이브카; 시작한다.      한다면 (FDriver.나이 <=> 16)         그리고나서 기입('죄송합니다, 운전자는 운전하기에 너무 어립니다.')         또 다른 프릴카.드라이브카(); 끝.;  끝.. 

사용.

프로그램. 프로젝트 1; {$APPTYPE 콘솔} 사용하다     디자인 패턴.프록시  'DesignPattern(디자인 패턴)'Proxy.pas'; 시작한다.      TPoxyCar.신규(TDriver.신규(16)).드라이브카;      TPoxyCar.신규(TDriver.신규(25)).드라이브카; 끝.. 

산출량

미안해요, 운전하기엔 너무 어려요.차가 운행되었습니다! 

자바

다음 Java 예는 "가상 프록시" 패턴을 보여 줍니다.ProxyImage원격 메서드에 액세스하기 위해 class가 사용됩니다.

이 예에서는 처음에 패턴이 클래스를 작성하는 인터페이스를 만듭니다.이 인터페이스에는 이미지를 표시하는 방법이1개밖에 없어요displayImage()이를 구현하는 모든 클래스가 코드화해야 합니다.

프록시 클래스ProxyImage실제 이미지 클래스 자체와는 다른 시스템에서 실행되며 실제 이미지를 나타낼 수 있습니다.RealImage저기.디스크에서 이미지 정보에 액세스합니다.프록시 패턴을 사용하여,ProxyImage는 이미지를 여러 번 로드하지 않고 메모리를 절약하여 다른 시스템에서 액세스할 수 있습니다.이 예에서 보여지는 느린 로드는 프록시 패턴의 일부가 아니라 프록시를 사용함으로써 가능한 이점일 뿐입니다.

인터페이스 이미지 {     일반의 무효 표시 이미지(); }  // 시스템 A의 경우 학급 리얼 이미지 용구 이미지 {     사적인 최종 스트링 파일명;      /** * 컨스트럭터 * @filename 파일명 */     일반의 리얼 이미지(스트링 파일명) {         이것..파일명 = 파일명;         load Image From Disk();     }      /** * 디스크에서 이미지를 로드합니다. */     사적인 무효 load Image From Disk() {         시스템..나가..인쇄("로드 중" + 파일명);     }      /** * 이미지 표시 */     일반의 무효 표시 이미지() {         시스템..나가..인쇄("표시 중" + 파일명);     } }  // 시스템 B의 경우 학급 프록시 이미지 용구 이미지 {     사적인 최종 스트링 파일명;     사적인 리얼 이미지 이미지;          /** * 컨스트럭터 * @filename 파일명 */     일반의 프록시 이미지(스트링 파일명) {         이것..파일명 = 파일명;     }      /** * 이미지 표시 */     일반의 무효 표시 이미지() {         한다면 (이미지 == 무효) {            이미지 = 신규 리얼 이미지(파일명);         }         이미지.표시 이미지();     } }  학급 프록시 예시 {    /** * 시험방법 */    일반의 정적인 무효 주된(최종 스트링[] 논쟁들) {         이미지 이미지 1 = 신규 프록시 이미지("HiRes_10MB_Photo1");         이미지 이미지2 = 신규 프록시 이미지("HiRes_10MB_Photo2");          이미지 1.표시 이미지(); // 로드 필요         이미지 1.표시 이미지(); // 로드 불필요         이미지2.표시 이미지(); // 로드 필요         이미지2.표시 이미지(); // 로드 불필요         이미지 1.표시 이미지(); // 로드 불필요     } } 

산출량

HiRes_10MB_Photo1 디스플레이 HiRes_10MB_Photo1 디스플레이 HiRes_10MB_Photo1 로드 HiRes_10MB_Photo2 디스플레이 HiRes_10MB_Photo2 디스플레이 HiRes_10MB_Photo2 디스플레이 HiRes_10MB 디스플레이

자바스크립트

// 드라이버 클래스 학급 드라이버 {   컨스트럭터 (나이) {     이것..나이 = 나이   } }  // 자동차 클래스 학급  {   운전해. () {     콘솔.로그.('차가 운행되었습니다!')   } }  // 프록시 카 클래스 학급 프록시카 {   컨스트럭터 (드라이버) {     이것.. = 신규 ()     이것..드라이버 = 드라이버   }    운전해. () {     한다면 (이것..드라이버.나이 <=> 16) {       콘솔.로그.('죄송합니다, 운전자는 운전하기에 너무 어립니다.')     } 또 다른 {       이것...운전해.()     }   } }  // 프로그램 실행 컨스턴트 드라이버 = 신규 드라이버(16) 컨스턴트  = 신규 프록시카(드라이버) .운전해.()  컨스턴트 드라이버 2 = 신규 드라이버(25) 컨스턴트 카2 = 신규 프록시카(드라이버 2) 카2.운전해.() 

산출량

미안해요, 운전하기엔 너무 어려요.차가 운행되었습니다! 

고급 프록시에는Proxy오브젝트: 속성 접근과 같은 기본 조작을 대행 수신하고 재정의할 수 있습니다.이 경우 핸들러 함수는 [4]트랩이라고 불리기도 합니다.

PHP

<?개요   인터페이스 이미지 {     일반의 기능. 표시 이미지(); }  // 시스템 A의 경우 학급 리얼 이미지 용구 이미지 {     사적인 스트링 $140 = 무효;      일반의 기능. __개요(스트링 $140)     {         $ this->파일명 = $140;         $ this->load Image From Disk();     }      /** * 디스크에서 이미지를 로드합니다. */     사적인 기능. load Image From Disk()     {         메아리치다 "로드 중{$ this->파일명}" . \PHP_EOL;     }      /** * 이미지 표시 */     일반의 기능. 표시 이미지()     {      메아리치다 '표시 중'{$ this->파일명}" . \PHP_EOL;     } }  // 시스템 B의 경우 학급 프록시 이미지 용구 이미지 {     사적인 ?이미지 $이미지 = 무효;     사적인 스트링 $140 = 무효;      일반의 기능. __개요(스트링 $140)     {         $ this->파일명 = $140;     }      /** * 이미지 표시 */     일반의 기능. 표시 이미지()     {         한다면 ($ this->이미지 === 무효) {            $ this->이미지 = 신규 리얼 이미지($ this->파일명);         }         $ this->이미지->표시 이미지();     } }   $image1 = 신규 프록시 이미지("HiRes_10MB_Photo1"); $image2 = 신규 프록시 이미지("HiRes_10MB_Photo2");  $image1->표시 이미지(); // 로드 필요 $image1->표시 이미지(); // 로드 불필요 $image2->표시 이미지(); // 로드 필요 $image2->표시 이미지(); // 로드 불필요 $image1->표시 이미지(); // 로드 불필요 

산출량

HiRes_10MB_Photo1 디스플레이 HiRes_10MB_Photo1 디스플레이 HiRes_10MB_Photo1 로드 HiRes_10MB_Photo2 디스플레이 HiRes_10MB_Photo2 디스플레이 HiRes_10MB_Photo2 디스플레이 HiRes_10MB 디스플레이

파이썬

""" 프록시 패턴의 예시. """ 부터 abc 수입품 ABC메타, 추상적 방법   미실장 = "이것을 구현해야 합니다."   학급 추상 자동차:     __메타클래스__ = ABC메타      @http 방법     방어하다 운전해.(자신):         올리다 구현되지 않은 오류(미실장)   학급 (추상 자동차):     방어하다 운전해.(자신) -> 없음.:         인쇄물("차가 운행되었습니다!")   학급 드라이버:     방어하다 __init__(자신, 나이: 인트) -> 없음.:         자신.나이 = 나이   학급 프록시카(추상 자동차):     방어하다 __init__(자신, 드라이버) -> 없음.:         자신. = ()         자신.드라이버 = 드라이버      방어하다 운전해.(자신) -> 없음.:         한다면 자신.드라이버.나이 <=> 16:             인쇄물("죄송합니다, 운전자는 운전하기에 너무 어립니다.")         또 다른:             자신..운전해.()   드라이버 = 드라이버(16)  = 프록시카(드라이버) .운전해.()  드라이버 = 드라이버(25)  = 프록시카(드라이버) .운전해.() 

산출량

미안해요, 운전하기엔 너무 어려요.차가 운행되었습니다! 

특성 ICar{2drive(&self).}구조 자동차{}impl ICar 자동차{fn drive(&self){println!("자동차 주도되었다!");}에}자동차{fn new()->, 자동차{자동차{}impl}}structProxyCar<, 'a>,{real_car:&ICar 'a, driver_age:i32,}impl<, 'a>, ICar ProxyCar&lt을 위해;'a>,{fn drive(&self){만약self.driver_age>16{.self.real_car.drive().}일 경우 다른{println!("드라이버가 너무 어려서 운전할 수 없습니다." ) } } } } include <'a> { fn new(driver_age: i32, other_car: &'a ICar) -> ProxyCar { real_car: other_car, driver_age: driver_age, } } } } } } } :*; #[test] fn test_drive() {let car = Car::new(); let proxy_car = ProxyCar::new (16, &car); } #[test] fn test_can_drive() {let car = ProxyCar:new (17)

산출량

미안하지만, 그 차는 네가 운전하기에 너무 젊다.차가 운행되었습니다! 

「 」를 참조해 주세요.

레퍼런스

  1. ^ Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley. pp. 207ff. ISBN 0-201-63361-2.{{cite book}}: CS1 maint: 여러 이름: 작성자 목록(링크)
  2. ^ "The Proxy design pattern - Problem, Solution, and Applicability". w3sDesign.com. Retrieved 2017-08-12.
  3. ^ "The Proxy design pattern - Structure and Collaboration". w3sDesign.com. Retrieved 2017-08-12.
  4. ^ "Proxy - JavaScript MDN". developer.mozilla.org. Retrieved 21 January 2022.

외부 링크