본문 바로가기
소프트웨어공학/디자인 패턴

Proxy Pattern 프록시 패턴 - 구조, Heavy object를 대리할 light object를 생성 | Design pattern 디자인 패턴

by javapp 자바앱 2021. 12. 4.
728x90

 

Proxy Pattern

 

 

프록시 패턴은 surrogate 와 다른 객체의 접근에 대한 통제를 할 수 있는 placeholder를 제공한다.

 

  • 객체의 대리자를 이용하여 다른 객체로의 접근을 통제하는 패턴
  • 대리 객체를 통해 원래 객체의 작업을 대신 수행
  • 복잡한 작업과 단순한 작업을 나누어서 처리
  • 원래의 기능을 수행하면서 부가적인 기능을 수행할 때 유용

 


 

문제점)

  • 객체 생성에 비용(시간, 자원)이 많이 드는 Heavy object 가 있다.
  • 프로그램이 종료될 때까지 한 번도 사용되지 않으면 시간, 자원의 낭비가 있다.
  •  

Key Idea) Heavy object를 대리light object를 생성

- Heavy object와 동일한 인터페이스를 가지는 proxy (대리 객체)

  1. Heavy object 대신 proxy class 를 생성한다.
  2. 프록시의 메소드가 호출될 때 (실제 heavy object가 필요할 때) 프록시는 heavy object를 생성하고 작업을 위임한다.

 

 

 

Head First Design Patterns

 

 

위임을 위해 프록시도 동일한 인터페이스를 구현한다.

 

프록시는 RealSubject를 위임한다.

 

 

 

 

 

 

 

 

 

 

 

 

원격이 될 수 있고 생성에 리소스 비용이 많이 들거나 보안이 필요한 또 다른 객체(object)에 접근(access)을 통제하는 대리 객체를 생성하기 위해 프록시 패턴을 사용한다.

 

 

Proxy: 
doAction() {
	사전작업; 
	realSubject.doAction(); 
	사후작업; 
}

 

Proxy

public class Proxy implements Subject 
{
	//composition of null real subject
	private Subject s = null; //한번만 생성하면 된다.

	public void doAction() { // 인터페이스 메소드
		if (s == null) 
			s = new Subject();	// 실제 객체 생성
		s.doAction(); 			// 실제 객체에게 위임
	}
}

 

Client

// proxy 생성.
Proxy p = new Proxy();	

// subject method 호출시 
// real subject 생성.
if (cond) p.doAction();

 

 

 


 

 

 

 

Proxy Pattern 용도

 

 

Remote Proxy 

Remote 프록시는 다른 JVM에 있는 객체의 로컬 대표자 역할을 한다.

 

 

 

 

Virtual Proxy

가상 프록시는 생성에 비용이 많이 들 수 있는 객체의 대표자 역할을 한다.

Virtual Proxy는 필요할 때까지 개체 생성을 연기하는 경우가 많습니다.

프록시가 RealSubject 에게 직접 요청

 

 

 

 

Firewall Proxy

 

방화벽 시스템 주로 위치

네트워크 자원 접근이나 “bad” clients로 부터 the subject를 보호하는데에 컨트롤

 

 

 

 

 

Smart Reference Proxy

 

Subject 가 객체에 대한 참조 수 계산과 같이 참조하는 actions를 추가적으로 제공

 

 

 

 

 

Caching Proxy

 

content management and publishing systems 뿐만 아니라 웹 서버 프록시에 사용

캐싱 프록시는 비용이 많이 드는 작업 결과를 위한 임시 저장소를 제공한다.

여러 클라이언트가 결과를 공유하여 계산을 줄이고 네트워크 지연시간을 줄일 수 있습니다.

 

 

 

 

 

Synchronization Proxy

 

멀티 쓰레드로 부터 주제에 안전한 접근을 제공한다.

 

 

 

 

 

Complexity Hiding Proxy

 

복잡성을 숨기고 클래스들의 복잡한 셋에 접근을 제어한다.

The Facade Proxy 라고 부르지만 단지 대체 인터페이스를 제공

 

 

 

 

 

 

Copy-On-Write Proxy

 

클라이언트에 필요할 때까지 개체 복사를 지연하여 개체 복사를 제어합니다.

 

 

 

 

 


 

 

 

 

 

ex) Java Proxy API

 

Proxy, InvocationHandler : java.lang.reflect

 

 

Protection Proxy 구현

InvocationHandler

proxy에 대한 호출이 오면 메소드 호출을

real subject 메소드 호출로

변환함 (하는 규칙을 가짐)

생성시 구성

 

 

 

invoke 메소드

변환규칙 (호출 규칙)

public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException
{
   try   {      
   		if(method.getName().startsWith("get")){        
        		return method.invoke(person,args);   
   }...
}

- 프록시 메소드를 real object에 대한 호출로 변환한다.
- proxy.getName()), proxy에 의해 메소드가 불려진다.
- InvocationHandler 에 의해 invoke() 를 부른다.
- Method 클래스는 reflection API 이다. method는 프록시에 의해 getName()이 불려진다.
- return method.invoke(person,args);
- invoke가 Real Subject의 메소드를 부른다. (실 객체의 함수를 부른다.)

source code.zip
0.00MB

 

 

 


 

 

 

 

프록시 패턴 구현 예제

 

다이어 그램

인터페이스 : PersonBean

클래스 상속 : PersonBeanImpl, Proxy

 

PersonBeanImpl : PersonBean 의 구현 객체 (Heavy object)

Proxy : PersonBean을 구성 (light object)

 

 

 

 

 

소스코드

 

 

PersonBean

package Proxy.pattern;

public interface PersonBean
{
    String getName();
    String getInterests();
    int getRating();
    int getHotOrNotRating();

    void setName(String name);
    void setInterests(String interests);
    void setRating(int rating);
    void setHotOrNotRating(int rating);
}

 

PersonBeanImpl

package Proxy.pattern;

public class PersonBeanImpl implements PersonBean
{
    private String name;
    private String gender;
    private String interests;
    private int rating=0;
    private int ratingCount=0;

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getInterests() {
        return interests;
    }

    @Override
    public int getRating() {
        return rating;
    }

    @Override
    public int getHotOrNotRating() {

        System.out.println(rating + " " +ratingCount);
        if(ratingCount == 0)return 0;
        return (rating/ratingCount);
    }


    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setInterests(String interests) {
        this.interests = interests;
    }

    @Override
    public void setRating(int rating) {
        this.rating += rating;
    }

    @Override
    public void setHotOrNotRating(int rating) {
        this.rating += rating;
        ratingCount++;
    }
}

 

Proxy

package Proxy.pattern;

public class Proxy implements PersonBean
{
    PersonBean personBean;

    public Proxy(PersonBean personBean) {
        this.personBean = personBean;
    }

    private String name;
    private String gender;
    private String interests;
    private int rating=0;
    private int ratingCount=0;

    @Override
    public String getName() {

        return (personBean != null) ? personBean.getName() : name;
    }

    @Override
    public String getInterests() {
        return (personBean != null) ? personBean.getInterests() : interests;
    }

    @Override
    public int getRating() {
        return (personBean != null) ? personBean.getRating() : rating;
    }

    @Override
    public int getHotOrNotRating() {
        if(personBean != null){
            return personBean.getHotOrNotRating();
        }else {
            if (ratingCount == 0) return 0;
            return (rating / ratingCount);
        }
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public void setInterests(String interests) {
        this.interests = interests;
    }
    @Override
    public void setRating(int rating) {
        this.rating += rating;
    }
    @Override
    public void setHotOrNotRating(int rating) {
        this.rating += rating;
        ratingCount++;
    }
}

 

Client

package Proxy.pattern;

public class Client {
    public static void main(String[] args) {
        // 객체 생성
        PersonBean hong = new PersonBeanImpl();
        hong.setName("길동"); hong.setInterests("Bike, music"); hong.setRating(7);

        Proxy p = new Proxy(hong);
        System.out.println("proxy name is : "+p.getName());
    }
}

 

 

 

 

실행결과

 

 

 

책 참고 : Head First Design Patterns

 

댓글