맨위로가기

프록시 패턴

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

프록시 패턴은 객체에 대한 접근을 제어하기 위한 디자인 패턴으로, 객체에 대한 대리자 역할을 하는 프록시 객체를 사용하여 실제 객체에 대한 접근을 관리한다. 프록시 패턴은 원격 프록시, 가상 프록시, 보호 프록시 등 다양한 형태로 구현될 수 있으며, 접근 제어, 지연 로딩, 원격 객체 접근, 로깅 및 모니터링 등 다양한 상황에서 활용된다. 가상 프록시는 객체 생성을 지연시켜 리소스 사용을 최적화하고, 보호 프록시는 접근 권한에 따라 리소스 접근을 제어한다.

더 읽어볼만한 페이지

  • 소프트웨어 디자인 패턴 - 모델-뷰-컨트롤러
    모델-뷰-컨트롤러(MVC)는 소프트웨어 디자인 패턴으로, 응용 프로그램을 모델, 뷰, 컨트롤러 세 가지 요소로 분리하여 개발하며, 사용자 인터페이스 개발에서 데이터, 표현 방식, 사용자 입력 처리를 분리해 유지보수성과 확장성을 높이는 데 기여한다.
  • 소프트웨어 디자인 패턴 - 스케줄링 (컴퓨팅)
    스케줄링은 운영 체제가 시스템의 목적과 환경에 맞춰 작업을 관리하는 기법으로, 장기, 중기, 단기 스케줄러를 통해 프로세스를 선택하며, CPU 사용률, 처리량 등을 기준으로 평가하고, FCFS, SJF, RR 등의 알고리즘을 사용한다.
프록시 패턴
소프트웨어 디자인 패턴
프록시 디자인 패턴의 UML 다이어그램
프록시 디자인 패턴의 UML 다이어그램
유형구조적 패턴
의도다른 객체에 대한 접근을 제어하기 위한 대체 객체 제공
별칭Surrograte (대리인)
Handle (핸들)
해결책래퍼 클래스 생성, 원래 클래스와 동일한 인터페이스, 원래 클래스에 대한 참조 포함
참가자주제 (Subject)
실제 주제 (RealSubject)
프록시 (Proxy)
협업클라이언트는 실제 주제 대신 프록시를 통해 작업 요청
프록시는 실제 주제에 요청 전달
결과실제 주제 접근 제어
추가 기능 제공 (로깅, 캐싱 등)
실제 주제 생성 비용 절감 (Lazy Initialization)
관련 패턴어댑터 패턴 (Adapter Pattern)
데코레이터 패턴 (Decorator Pattern)

2. 프록시 디자인 패턴의 구조 및 종류

프록시 디자인 패턴은 크게 세 가지 주요 유형으로 분류할 수 있다.


  • 원격 프록시 (Remote Proxy): 분산 객체 통신에서 로컬 객체가 다른 주소 공간에 있는 원격 객체를 나타낸다. 로컬 객체는 원격 객체의 프록시 역할을 하며, 로컬 객체의 메서드를 호출하면 원격 객체에 대한 원격 메서드 호출(RMI)이 발생한다. 예를 들어, ATM는 원격 서버에 있는 은행 정보를 위한 프록시 객체를 가질 수 있다.
  • 가상 프록시 (Virtual Proxy): 생성 비용이 큰 객체의 생성을 필요한 시점까지 지연시킨다. 실제 객체가 사용될 때까지 가벼운 프록시 객체가 사용되며, 실제 객체가 필요한 시점에 생성되어 작업을 위임받는다. 이를 통해 리소스 사용을 최적화하고 애플리케이션의 초기 로딩 시간을 단축할 수 있다. 고해상도 이미지 로딩을 지연시키는 이미지 프록시가 그 예이다.[1]
  • 보호 프록시 (Protection Proxy): 접근 권한에 따라 리소스 접근을 제어한다.[1] C# 예제에서 `RealClient`는 계정 번호를 저장하고, 올바른 비밀번호를 아는 사용자만 `ProtectionProxy`를 통해 계정 번호에 접근할 수 있는 것이 그 예이다.[1]

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

프록시 디자인 패턴의 샘플 UML 클래스 및 시퀀스 다이어그램.


위의 UML 클래스 다이어그램에서 `Proxy` 클래스는 `Subject` 인터페이스를 구현하여 `Subject` 객체를 대신할 수 있도록 한다. 프록시는 대체된 객체(`RealSubject`)에 대한 참조(`realSubject`)를 유지하여 해당 객체에 요청을 전달할 수 있다(`realSubject.operation()`).

UML의 프록시


시퀀스 다이어그램은 런타임 상호 작용을 보여준다. `Client` 객체는 `RealSubject` 객체에 대한 접근을 제어하는 `Proxy` 객체를 통해 작동한다. 이 예에서 `Proxy`는 요청을 `RealSubject`로 전달하고, `RealSubject`는 요청을 수행한다.

LePUS3의 프록시

2. 2. 원격 프록시 (Remote Proxy)

분산 객체 통신에서, 로컬 객체는 다른 주소 공간에 있는 원격 객체를 나타낸다. 로컬 객체는 원격 객체의 프록시이며, 로컬 객체에 대한 메서드 호출은 원격 객체에 대한 원격 메서드 호출(RMI)로 이어진다. 예를 들어 ATM 구현에서, ATM은 원격 서버에 존재하는 은행 정보를 위한 프록시 객체를 가질 수 있다.

2. 3. 가상 프록시 (Virtual Proxy)

가상 프록시는 생성 비용이 높은 객체의 생성을 필요한 시점까지 지연시키는 역할을 한다. 실제 객체가 사용될 때까지 가벼운 프록시 객체가 대신 사용되며, 실제 객체의 생성이 필요한 시점에 실제 객체를 생성하고 작업을 위임한다. 이를 통해 리소스 사용을 최적화하고 애플리케이션의 초기 로딩 시간을 단축할 수 있다. 예를 들어, 고해상도 이미지 로딩을 지연시키는 이미지 프록시가 있다.[1]

복잡하거나 무거운 객체를 대신하여, 일부 경우에는 골격 표현이 유리할 수 있다. 기본 이미지가 크기가 매우 큰 경우, 가상 프록시 객체를 사용하여 표현하고, 필요에 따라 실제 객체를 로드할 수 있다.[1]

다음은 Java의 예시로, "가상 프록시" 패턴을 보여준다.[1]

```java

import java.util.*;

interface Image {

public void displayImage();

}

class RealImage implements Image {

private String filename;

public RealImage(String filename) {

this.filename = filename;

loadImageFromDisk();

}

private void loadImageFromDisk() {

// 시간이 오래 걸리는 일련의 작업

// ...

System.out.println("Loading "+filename);

}

public void displayImage() { System.out.println("Displaying "+filename); }

}

class ProxyImage implements Image {

private String filename;

private Image image;

public ProxyImage(String filename) { this.filename = filename; }

public void displayImage() {

if (image == null) {

image = new RealImage(filename); // 로딩은 온디맨드로만 수행된다.

}

image.displayImage();

}

}

class ProxyExample {

public static void main(String[] args) {

Image image1 = new ProxyImage("HiRes_10MB_Photo1");

Image image2 = new ProxyImage("HiRes_10MB_Photo2");

Image image3 = new ProxyImage("HiRes_10MB_Photo3");

image1.displayImage(); // 로딩이 필요함

image2.displayImage(); // 로딩이 필요함

image2.displayImage(); // 이미 로딩되었으므로 로딩 불필요

// image3의 이미지는 한 번도 로딩되지 않음

}

}

```

`ProxyImage` 클래스는 실제로 필요할 때까지 시간이 오래 걸리는 이미지 파일 로딩을 지연시킨다. 파일이 결국 필요하지 않은 경우, 시간이 오래 걸리는 로딩은 전혀 수행되지 않는다.[1]

2. 4. 보호 프록시 (Protection Proxy)

보호 프록시는 접근 권한에 따라 리소스에 대한 접근을 제어하는 데 사용될 수 있다.[1] 다음 C# 예제에서 `RealClient`는 계정 번호를 저장한다. 올바른 비밀번호를 알고 있는 사용자만 이 계정 번호에 접근할 수 있으며, `RealClient`는 비밀번호를 알고 있는 `ProtectionProxy`에 의해 보호된다. 사용자가 계정 번호를 얻고 싶어하는 경우, 먼저 프록시가 사용자에게 인증을 요구하고, 사용자가 올바른 비밀번호를 입력했을 때만 프록시가 `RealClient`를 호출하여 계정 번호를 사용자에게 통지한다.[1]

이 예제에서 올바른 비밀번호는 '''thePassword'''이다.[1]



using System;

namespace ConsoleApplicationTest.FundamentalPatterns.ProtectionProxyPattern

{

public interface IClient {

string GetAccountNo();

}

public class RealClient : IClient {

private string accountNo = "12345";

public RealClient() {

Console.WriteLine("RealClient: Initialized");

}

public string GetAccountNo() {

Console.WriteLine("RealClient's AccountNo: " + accountNo);

return accountNo;

}

}

public class ProtectionProxy : IClient

{

private string password; //비밀 비밀번호

RealClient client;

public ProtectionProxy(string pwd) {

Console.WriteLine("ProtectionProxy: Initialized");

password = pwd;

client = new RealClient();

}

// 사용자를 인증하고 계정 번호를 반환합니다.

public String GetAccountNo() {

Console.Write("Password: ");

string tmpPwd = Console.ReadLine();

if (tmpPwd == password) {

return client.GetAccountNo();

} else {

Console.WriteLine("ProtectionProxy: Illegal password!");

return "";

}

}

}

class ProtectionProxyExample

{

[STAThread]

public static void Main(string[] args) {

IClient client = new ProtectionProxy("thePassword");

Console.WriteLine();

Console.WriteLine("main received: " + client.GetAccountNo());

Console.WriteLine("\nPress any key to continue . . .");

Console.Read();

}

}

}


3. 프록시 디자인 패턴의 활용

프록시 디자인 패턴은 다음과 같은 상황에서 유용하게 활용될 수 있다.


  • 접근 제어 및 보안: 접근 권한에 따라 리소스에 대한 접근을 제어한다.
  • 지연 로딩 (Lazy Loading): 복잡하거나 무거운 객체를 대신하여 가상 프록시 객체를 사용하고, 필요에 따라 실제 객체를 로드한다.[1]
  • 원격 객체 접근: 분산 객체 통신에서 로컬 객체는 원격 객체를 나타내며, 로컬 객체에 대한 메서드 호출은 원격 메서드 호출로 이어진다. (ATM 예시)

3. 1. 접근 제어 및 보안

보호 프록시는 접근 권한에 따라 리소스에 대한 접근을 제어하는 데 사용될 수 있다.

3. 2. 지연 로딩 (Lazy Loading)

복잡하거나 무거운 객체를 대신하여, 일부 경우에 골격 표현이 유리할 수 있다. 기본 이미지가 크기가 매우 큰 경우, 가상 프록시 객체를 사용하여 표현하고, 필요에 따라 실제 객체를 로드할 수 있다.[1]

3. 3. 원격 객체 접근

분산 객체 통신에서 로컬 객체는 원격 객체(다른 주소 공간에 속한 객체)를 나타낸다. 로컬 객체는 원격 객체의 프록시이며, 로컬 객체에 대한 메서드 호출은 원격 객체에 대한 원격 메서드 호출로 이어진다. 예를 들어 ATM 구현에서, ATM은 원격 서버에 존재하는 은행 정보를 위한 프록시 객체를 가질 수 있다.

4. 예제 코드

Java와 C#을 사용한 프록시 패턴 예제가 있다. Java 예제는 가상 프록시를 통해 이미지 로딩을 지연시켜 불필요한 로딩을 방지한다. C# 예제는 보호 프록시를 사용하여 계좌 정보 접근을 제어하는데, 올바른 비밀번호를 입력해야만 접근 가능하다.

4. 1. Java 예제

다음은 Java를 사용한 가상 프록시 패턴 예제이다. `ProxyImage` 클래스는 실제 이미지가 필요할 때까지 이미지 로딩을 지연시킨다. 만약 이미지가 필요하지 않다면, 시간이 오래 걸리는 로딩은 수행되지 않는다.

```java

import java.util.*;

interface Image {

public void displayImage();

}

class RealImage implements Image {

private String filename;

public RealImage(String filename) {

this.filename = filename;

loadImageFromDisk();

}

private void loadImageFromDisk() {

System.out.println("Loading " + filename);

}

@Override

public void displayImage() {

System.out.println("Displaying " + filename);

}

}

class ProxyImage implements Image {

private String filename;

private Image image;

public ProxyImage(String filename) {

this.filename = filename;

}

@Override

public void displayImage() {

if (image == null)

image = new RealImage(filename);

image.displayImage();

}

}

class ProxyExample {

public static void main(String[] args) {

Image image1 = new ProxyImage("HiRes_10MB_Photo1");

Image image2 = new ProxyImage("HiRes_10MB_Photo2");

image1.displayImage(); // 로딩 필요

image2.displayImage(); // 로딩 필요

}

}

```
실행 결과:```text

Loading HiRes_10MB_Photo1

Displaying HiRes_10MB_Photo1

Loading HiRes_10MB_Photo2

Displaying HiRes_10MB_Photo2

4. 2. C# 예제

다음은 보호 프록시를 사용하여 계좌 정보 접근을 제어하는 C# 예제이다.

```csharp

using System;

namespace ConsoleApplicationTest.FundamentalPatterns.ProtectionProxyPattern

{

public interface IClient {

string GetAccountNo();

}

public class RealClient : IClient {

private string accountNo = "12345";

public RealClient() {

Console.WriteLine("RealClient: Initialized");

}

public string GetAccountNo() {

Console.WriteLine("RealClient's AccountNo: " + accountNo);

return accountNo;

}

}

public class ProtectionProxy : IClient

{

private string password; //비밀 비밀번호

RealClient client;

public ProtectionProxy(string pwd) {

Console.WriteLine("ProtectionProxy: Initialized");

password = pwd;

client = new RealClient();

}

// 사용자를 인증하고 계정 번호를 반환합니다.

public String GetAccountNo() {

Console.Write("Password: ");

string tmpPwd = Console.ReadLine();

if (tmpPwd == password) {

return client.GetAccountNo();

} else {

Console.WriteLine("ProtectionProxy: Illegal password!");

return "";

}

}

}

class ProtectionProxyExample

{

[STAThread]

public static void Main(string[] args) {

IClient client = new ProtectionProxy("thePassword");

Console.WriteLine();

Console.WriteLine("main received: " + client.GetAccountNo());

Console.WriteLine("\nPress any key to continue . . .");

Console.Read();

}

}

}

```

`RealClient`는 계정 번호를 저장한다. 올바른 비밀번호를 알고 있는 사용자만 이 계정 번호에 접근할 수 있다. `RealClient`는 비밀번호를 알고 있는 `ProtectionProxy`에 의해 보호된다. 사용자가 계정 번호를 얻고 싶어하는 경우, 먼저 프록시가 사용자에게 인증을 요구하고, 사용자가 올바른 비밀번호를 입력했을 때만 프록시가 `RealClient`를 호출하여 계정 번호를 사용자에게 통지한다.

이 예제에서 올바른 비밀번호는 '''thePassword'''이다.

참조

[1] 서적 Design Patterns: Elements of Reusable Object-Oriented Software https://archive.org/[...] Addison Wesley
[2] 웹사이트 The Proxy design pattern - Problem, Solution, and Applicability http://w3sdesign.com[...] 2017-08-12
[3] 웹사이트 The Proxy design pattern - Structure and Collaboration http://w3sdesign.com[...] 2017-08-12



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com