배워서 남 주자

디자인 패턴 - Proxy 패턴

미래에서 온 개발자 2023. 10. 17. 18:03

Proxy 패턴

  • Proxy는 다른 사람의 '대리인'이라는 의미
  • Proxy 패턴은 해당 객체를 직접 다루는 것이 아니라 Proxy 객체와 인터렉션하는 것이다.  
  • Proxy 클래스의 두 번째 인자는 핸들러이다. 핸들러 객체에서 인터렉션의 종류에 따른 특정 동작들을 정의할 수 있다.
const person = {
  name: "John Doe",
  age: 42,
  nationality: "American"
};

const personProxy = new Proxy(person, {
  get: (obj, prop) => {
    console.log(`The value of ${prop} is ${obj[prop]}`);
  },
  set: (obj, prop, value) => {
    console.log(`Changed ${prop} from ${obj[prop]} to ${value}`);
    obj[prop] = value;
    return true;
  }
});

personProxy.name; // 'The value of name is John Doe'
personProxy.age = 43; // 'Changed age from 42 to 43'

person; // {name: 'John Doe', age: 43, nationality: 'American'}

 

Use Case : 유효성 검사 

  • 사용자는 person 객체의 age 프로퍼티를 문자열로 수정할 수 없고 또는 name 프로퍼티를 빈 문자열로 초기화할 수 없다. 그리고 사용자가 person 객체에 존재하지 않는 프로퍼티에 접근하려 하면 알려줄 수 있다.
  • Proxy를 통해 대상 객체를 실수로 수정하는 것을 예방해주어 데이터를 안전하게 관리할 수 있다.
const personProxy = new Proxy(person, {
  get: (obj, prop) => {
    if (!obj[prop]) {
      console.log(
        `Hmm.. this property doesn't seem to exist on the target object`
      )
    } else {
      console.log(`The value of ${prop} is ${obj[prop]}`)
    }
  },
  set: (obj, prop, value) => {
    if (prop === 'age' && typeof value !== 'number') {
      console.log(`Sorry, you can only pass numeric values for age.`)
    } else if (prop === 'name' && value.length < 2) {
      console.log(`You need to provide a valid name.`)
    } else {
      console.log(`Changed ${prop} from ${obj[prop]} to ${value}.`)
      obj[prop] = value
    }
  },
})

 

Reflect

  • 중간에서 가로챌 수 있는 JavaScript 작업에 대한 메소드를 제공하는 내장 객체로 메소드의 종류는 프록시 핸들러의 메소드와 인자 또한 동일하다.
  • Proxy와 함께 사용하면 대상 객체를 쉽게 조작할 수 있다.
const personProxy = new Proxy(person, {
  get: (obj, prop) => {
    console.log(`The value of ${prop} is ${Reflect.get(obj, prop)}`);
  },
  set: (obj, prop, value) => {
    console.log(`Changed ${prop} from ${obj[prop]} to ${value}`);
    return Reflect.set(obj, prop, value);
  }
});

 

Reflect를 사용하는 이유: 

 

  1. 더 명확한 함수 형태
    • 일반적으로 JavaScript에서 객체에 대한 연산을 수행할 때는 연산자(예: obj[prop], delete obj[prop] 등)를 사용한다. Reflect는 이러한 연산을 함수 형태로 제공하여 코드의 의도를 더 명확하게 만들 수 있다. 예를 들어, Reflect.get(obj, prop)은 obj[prop]와 동일한 연산을 수행하지만 함수 형태로 제공된다.
  2. 표준화된 반환으로 더 쉬운 오류 처리
    • 기존의 몇몇 내장 연산들은 오류 발생 시 예외를 던지기도 하고, 단순히 false 값을 반환하기도 한다. Reflect의 메소드들은 일관된 방식으로 연산의 성공 여부를 나타내는 불리언 값을 반환한다. 예를 들어, Reflect.defineProperty()는 성공 시 true, 실패 시 false를 반환한다. 이는 오류 처리를 보다 명확하게 할 수 있게 한다.
  3. Proxy와의 연계
    • Reflect와 Proxy는 서로 연계되어 동작하는 경우가 많다. 위에서 예제처럼 Proxy의 핸들러 함수 내에서 Reflect를 사용하면, 대상 객체에 대한 기본 동작을 재사용하거나 수정하는 것이 더욱 직관적이고 쉬워진다.

 

 

장점

  • 유효성 검사, formatting, 알림, 디버깅 등 유용하게 사용된다.

 

 

단점

  • 핸들러 객체에서 Proxy를 너무 헤비하게 사용하면 앱의 성능에 부정적인 영향을 줄 수 있다.

 

 

React에서 프록시 서버

프록시 패턴을 들여다보고 나니 프록시를 통해 CORS 정책을 우회하는 것이 결국은 프록시가 브라우저를 대리하여 프론트엔드에서 백엔드 서버와 요청과 응답을 주고 받는다는 것을 이해하게 되었다. 

proxy를 사용하면 백엔드 서버는 응답을 프론트엔드(리액트 앱)으로 보내고, 프론트엔드는 받은 응답을 서버 대신 브라우저에게 전달하기 때문에 출처가 같아져 CORS 정책을 우회할 수 있는 것이다. 

 

proxy 적용 전 흐름
proxy 적용 후 흐름

'배워서 남 주자' 카테고리의 다른 글

super 키워드  (1) 2023.10.22
Object.assign()  (0) 2023.10.19
디자인 패턴 - Provider 패턴  (0) 2023.10.15
디자인 패턴 - Factory 패턴  (0) 2023.10.15
디자인 패턴 - Prototype 패턴  (0) 2023.10.11