EunHee-Jeong/TIL

구조 패턴 - proxy

Closed this issue · 0 comments

구조 패턴 - Proxy란?

  • 원본 객체는 숨기고, 대신 동작하는 객체의 제한된 접근으로 컨트롤하는 디자인 패턴
  • 원본 객체에 대한 동일한 인터페이스를 제공한다.
  • 객체에 접근할 때, 원본 객체의 클라이언트 대신 proxy를 사용한다. 대리자 개념인 셈이다.
  • 원본 객체의 요청 전후로, proxy는 자신의 logic을 주입한다.
  • lazy 초기화와 객체에 대한 접근을 보호할 수 있다.

image

가장 흔한 예시

1. Remote Proxy

  • 주로 웹 서비스에서 이용한다.
    • 예시를 들자면 네트워크를 통해 request를 차례로 전달하는 프록시를 사용하는 것 …
  • 네트워크 호출의 복잡성을 줄일 수 있다.
  • remote 서비스를 local 개념으로 사용할 수 있게 해준다.

2. Virtual Proxy

  • 말 그대로 가상 프록시다.

  • 첫 사용 전까지 원본 객체의 생성을 지연시킨다.

    lazy 초기화 (Swift에서 built-in으로 제공하기는 함)

3. Protective Proxy

  • 민감한 객체로의 접근을 제어한다.
  • 보호하고자 하는 객체에 request를 위임하기 전에 먼저 프록시가 호출자를 확인한다.

코드 예시

소스 코드

import Foundation

public protocol DataBaseController {
    func save()
    func undo()
}

// 프로토콜을 채택할 타입 정의.
public class CoreDataManager: DataBaseController {
    public init() {
        // 객체 생성
        sleep(3)    // 확인을 위해 시간 걸어줌
    }
    
    public func save() {
        print("All changes saved")
    }
    
    public func undo() {
        print("All changes reverted")
    }
}

// 팩토리 메서드 선언
public func makeDatabaseController() -> DataBaseController {
    CoreDataManager()
}

// proxy
public class CoreDataProxy: DataBaseController {    // 같은 인터페이스 가짐을 확인 가능
    private var realManager: CoreDataManager?   // proxy
    private var coreDataManager: CoreDataManager? {
        guard let result = realManager else {
            realManager = CoreDataManager()
            return realManager
        }
        return result
    }
    
    private lazy var coreDataManager2: CoreDataManager? = CoreDataManager()
    // lazy는 계산 속성을 넣을 수 없기 때문에 옵셔널 체이닝으로 선언했음
    
    // ⬆️ 클라이언트가 메서드를 처음 호출하는 시점에 계산됨 (Virtual Proxy에 해당)
    /*
     무거운 객체의 자원을 곧장 생성하는 대신에,
     실제로 필요할 때까지만 초기화를 지연시켜
     최종 수정이 필요한 경우에만 팩토리 메서드가 프록시 인스턴스를 반납하고 원본 객체를 사용하도록 동작함
     */
    
    public func save() {
        coreDataManager.save()
        print("All changes saved")
    }
    
    public func undo() {
        coreDataManager.undo()
        print("All changes reverted")
    }
}

실행 부분

import Foundation

// database controller 객체 simulate

print("App 로딩 중 . . .")

let dbController = makeDatabaseController()

print("준비")

// ...
//dbController.save()

// 즉 지연 초기화를 통해 App의 로딩시간을 향상시킬 수 있다.
// 실제로 필요할 때만 사용하기 때문

let contextChanged = false

if contextChanged {
    dbController.save()
}

dbController.undo()
dbController.save()

정리

  • 정리하자면, proxy 디자인 패턴은 실제 객체를 placeholder (= 자리 표시자) 뒤에 숨긴다 !

  • 주로 사용되는 proxy들

    1. Remote Proxy
      • remote 객체의 local placeholder로서 동작
    2. Virtual Proxy
      • 크기가 거대한 자원의 생성을 관리
      • 첫 접근 이전까지 생성을 지연시키는 방식
    3. Protective Proxy
      • 보호된 자원에 접근하기 전에, 호출이 허가되었는지 확인
  • 주의점

    image

    • proxy로 인해 client 측의 변화가 당겨져서는 안 된다.

참고 및 그림 출처