EEALL@ONCE

🔦 프록시 객체가 뭔데? - 옵저버 패턴에 사용 본문

분류없음지식🔦

🔦 프록시 객체가 뭔데? - 옵저버 패턴에 사용

올엣원스 2023. 12. 13. 13:29
728x90

프록시 객체: 프록시는 실제 객체를 대신하여 기능을 수행하는 객체입니다. 보안, 지연 로딩, 분산 처리 등과 같은 목적으로 사용됩니다.

 

옵저버 패턴을 프록시 객체로 구현하는 시나리오를 상상해보면, 프록시 객체가 서브젝트의 대리 역할을 하면서 옵저버에게 상태 변경을 알리는 구조가 됩니다. 이 구조에서 프록시는 서브젝트의 메소드 호출을 관리하고, 필요한 경우 옵저버에게 상태 변경을 알립니다.

 

여기서 'Subject' 객체는 실제 로직을 담당하고, 'Proxy'는 Subject의 대리자로서 호출을 중계하고 옵저버들에게 상태 변화를 알립니다. 'Observer' 객체들은 상태 변화에 대한 알림을 받습니다. 이 다이어그램에서 화살표는 Subject에서 Proxy로, 그리고 Proxy에서 Observer로 정보가 흐르는 방향을 나타냅니다. 이러한 구조는 프록시가 Subject의 메소드 호출을 관리하고, 상태 변경이 있을 때 Observer에게 알리는 방식으로 작동합니다.


Observer 인터페이스:

javaCopy code
public interface Observer {
void update(String message); }

 

Observer 구현 클래스:

javaCopy code
public class ConcreteObserver implements Observer {
@Override public void update(String message) {
System.out.println("Received message: " + message); } }

 

Subject 인터페이스:

javaCopy code
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers(String message);
}

 

Subject 구현 클래스:

javaCopy code
import java.util.ArrayList; import java.util.List;
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void registerObserver(
Observer observer) { observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String message) {
for (Observer observer : observers) { observer.update(message); }
}
}

 

프록시 클래스:

avaCopy code
public class ProxySubject implements Subject {
private ConcreteSubject subject;
private boolean isChanged;
public ProxySubject(ConcreteSubject subject) {
this.subject = subject;
this.isChanged = false;
}
public void changeState() {
isChanged = true;
notifyObservers("State Changed");
}
@Override
public void registerObserver(Observer observer) {
subject.registerObserver(observer);
}
@Override
public void removeObserver(Observer observer) {
subject.removeObserver(observer);
}
@Override
public void notifyObservers(String message) {
if (isChanged) {
subject.notifyObservers(message);
isChanged = false; }
}
}
 
 

MAIN 

javaCopy code
public class Main {
public static void main(String[] args) {
ConcreteSubject realSubject = new ConcreteSubject();
ProxySubject proxy = new ProxySubject(realSubject);
Observer observer1 = new ConcreteObserver();
Observer observer2 = new ConcreteObserver();
proxy.registerObserver(observer1);
proxy.registerObserver(observer2);
proxy.changeState(); // 이 메소드 호출은 옵저버들에게 상태 변경을 알립니다.
}
}

ProxySubject 클래스는 실제 ConcreteSubject 객체의 메소드 호출을 관리하고, 상태 변경이 있을 때 (여기서는 changeState() 메소드 호출 시) 등록된 옵저버들에게 알립니다. ConcreteObserver 클래스는 간단한 메시지 출력을 통해 상태 변경을 확인할 수 있습니다.

 


프록시 객체를 사용하는 주된 이유는 실제 객체의 접근을 제어하고, 추가적인 기능을 제공하기 위해서입니다. 옵저버 패턴에 프록시를 도입하는 것은 다음과 같은 목적을 가질 수 있습니다:

  1. 접근 제어: 프록시는 실제 객체에 대한 접근을 제어할 수 있습니다. 예를 들어, 특정 조건에서만 객체의 메소드 호출을 허용하거나, 불필요한 호출을 방지할 수 있습니다.
  2. 추가 로직 구현: 프록시는 실제 객체의 메소드 호출 전후에 추가적인 로직을 실행할 수 있습니다. 이를 통해 로깅, 보안 검사, 캐싱 등의 기능을 구현할 수 있습니다.
  3. 상태 관리: 프록시는 내부 상태를 관리하여, 객체의 상태 변경 여부를 추적할 수 있습니다. 이를 통해 상태 변경이 있을 때만 옵저버들에게 알림을 보내는 등의 최적화를 할 수 있습니다.
  4. 리소스 관리: 프록시는 리소스 집약적인 객체를 대신하여, 리소스 사용을 효율적으로 관리할 수 있습니다. 예를 들어, 객체 생성 비용이 큰 경우, 프록시를 통해 필요할 때만 객체를 생성하거나, 생성된 객체를 재사용할 수 있습니다.
  5. 지연 초기화 (Lazy Initialization): 프록시는 객체의 지연 초기화를 가능하게 합니다. 객체의 생성과 초기화를 실제로 필요한 순간까지 지연시켜, 성능을 향상시킬 수 있습니다.
  6. 분산 시스템 지원: 원격 프록시는 분산 시스템에서 원격 객체의 접근을 쉽게 만듭니다. 클라이언트는 로컬 객체처럼 원격 객체를 사용할 수 있으며, 프록시가 네트워크 통신을 처리합니다.

프록시는 디자인 패턴에서 중요한 역할을 하며, 시스템의 유연성과 확장성을 향상시키는 데 기여합니다. 프록시를 통해 시스템의 다양한 부분을 느슨하게 결합하고, 관심사를 분리하여 코드의 관리와 유지보수를 용이하게 합니다.


🧐옵저버 패턴에서 프록시를 사용하는 이유는 뭐야?

옵저버 패턴에서 프록시를 사용하는 이유는 주로 세분화된 제어와 추가 기능 제공을 위해서입니다. 옵저버 패턴은 객체 간의 결합도를 낮추면서 상태 변화에 대해 여러 객체들이 자동으로 알림을 받을 수 있도록 하는 패턴입니다. 이때 프록시를 도입하면 다음과 같은 이점들을 얻을 수 있습니다:

  1. 제어된 통지 (Controlled Notification): 프록시를 통해 서브젝트의 상태 변경을 감시하고, 필요에 따라 옵저버에게 통지합니다. 이를 통해 불필요한 업데이트 호출을 줄이고, 통지 메커니즘을 좀 더 효율적으로 관리할 수 있습니다.
  2. 상태 변경 검증 (State Change Validation): 프록시는 서브젝트의 상태 변경을 검증하고, 실제로 중요한 변경이 발생했을 때만 옵저버에게 통지할 수 있습니다. 이를 통해 시스템의 오버헤드를 줄이고, 성능을 향상시킬 수 있습니다.
  3. 보안 (Security): 프록시를 사용하면 서브젝트에 대한 접근을 보다 세밀하게 제어할 수 있습니다. 이는 특정 옵저버가 서브젝트의 상태를 변경하는 것을 제한하거나, 보안 검증을 추가하는 데 유용합니다.
  4. 캐싱 (Caching): 프록시는 서브젝트의 상태를 일시적으로 저장하고, 이를 통해 옵저버에게 빠른 응답을 제공할 수 있습니다. 특히 대규모 시스템에서 이러한 캐싱 메커니즘은 성능 향상에 크게 기여할 수 있습니다.
  5. 동기화 (Synchronization): 멀티스레드 환경에서 프록시를 사용하면 서브젝트의 상태 변경을 동기화하고, 옵저버들에게 일관된 상태 정보를 제공할 수 있습니다.
  6. 추가 로직 구현 (Additional Logic Implementation): 프록시는 서브젝트의 메소드 호출 전후에 추가 로직을 실행할 수 있습니다. 예를 들어, 로깅, 트랜잭션 관리 등의 기능을 쉽게 추가할 수 있습니다.

프록시를 통해 옵저버 패턴의 유연성과 확장성을 높일 수 있으며, 복잡한 시스템에서 성능과 안정성을 향상시키는 데 도움이 됩니다.

 
 
 

객체 지향은 참 숨기는 걸 좋아한다. 

프록시 객체도 그러하다. 

SUBJECT의 보여주고 싶지 않은 정보를 숨기고 알려주고 싶은 최소의 정보만 알려주고자 하는거다.

프록시는 서브젝트의 권한이 제한된 버전인거고 

옵져버는 프록시를 통해서 제한된 정보만 받으면 되는거다. 

마치 대기업 고객사 같다. (보안은 생명이니까..라고 말해줫다. . ) 

 

728x90