[Design Patterns] Proxy 패턴

·2024년 1월 26일
0

patterns

목록 보기
2/11
post-thumbnail

Proxy 객체를 활용하면 특정 객체와의 인터렉션을 조금 더 컨트롤할 수 있게 된다. Proxy 객체는 어떤 객체의 값을 설정하거나 값을 조회할 때 등의 인터렉션을 직접 제어할 수 있다.

Proxy란

일반적으로 Proxy는 어떤 이의 대리인을 뜻한다. 그 사람과 직접 이야기하는 것 대신, 이야기를 원하는 사람의 대리인에게 이야기하는 것이다.
Javascript에서도 해당 객체를 직접 다루는 것이 아니고, Proxy 객체와 인터렉션하게 된다.

Proxy 객체

홍길동을 표현하는 객체 person을 만들어보자.

const person = {
  name: "John Doe",
  age: 42,
  nationality: "American",
}

이 객체와 직접 인터렉션하는 것 대신 Proxy 객체와 인터렉션해야 한다. Proxy 인스턴스를 만드는 것으로 쉽게 Proxy 객체를 만들어낼 수 있다.

const person = {
  name: "John Doe",
  age: 42,
  nationality: "American",
}

const personProxy = new Proxy(person, {})

Proxy 클래스의 두 번째 인자는 핸들러를 의미한다. 핸들러 객체에서 우리는 인터렉션의 종류에 따른 특정 동작들을 정의할 수 있다.
또한, 여러 메서드들을 추가할 수 있는데 일반적으로 getset이 있다.

  • get : 프로퍼티에 접근하려고 할 때 실행된다.
  • set : 프로퍼티에 값을 수정하려고 할 때 실행된다.

person 객체와 직접 인터렉션하는 것 대신 personProxy 객체와 인터렉션하게 된다.

personProxy 객체에 핸들러를 추가해보자. 프로퍼티를 수정하려 할 때는 앞서 말한 것과 같이 Proxyset 메서드가 호출되므로 이 핸들러 안에서 변경 전의 값과 변경 후의 값을 콘솔로 확인할 수 있다.
프로퍼티의 값을 읽으려고 할 때는 get 메서드가 호출되며 해당 키와 값에 대한 메시지를 콘솔에 출력할 수 있다.

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
  }
})

해당 값을 읽어오거나 수정하는 예제를 아래와 같이 확인해볼 수 있다.

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;
personProxy.age = 43;
  • name 프로퍼티에 접근하려고 할 때 Proxy 객체가 콘솔에 값을 출력해준다. : The value of name is John Doe
  • age 프로퍼티를 수정하려고 할 때 Proxy 객체가 변경 이전 값과 이후의 값을 콘솔에 출력한다. : Changed age from 42 to 43

Proxy와 유효성 검사

Proxy는 유효성 검사를 구현할 때 유용하다. 사용자는 person 객체의 age 프로퍼티를 문자열로 수정할 수 없으며 name 프로퍼티를 빈 문자열로 초기화할 수 없다. 또한 사용자가 person 객체에 존재하지 않는 프로퍼티에 접근하려 할 경우 알려준다.

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 ${object[prop]} to ${value}.`)
      obj[prop] = value
    }
  },
})

Reflect

Javascript는 Reflect라는 빌트인 객체를 제공하는데 Proxy와 함께 사용하면 대상 객체를 쉽게 조작할 수 있다.

이전 예제에서는 Proxy의 핸들러 내에서 괄호 표기를 사용하여 직접 프로퍼티를 수정하거나 읽을 수 있었는데, 그 대신 Reflect 객체를 사용할 수 있다. Reflect 객체의 메서드는 핸들러 객체와 같은 이름의 메서드를 가질 수 있다.

obj[prop] 형태로 프로퍼티에 직접 접근하거나 ojb[prop] = value 형태의 코드로 값을 수정하는 대신, Reflect.get() 혹은 Reflect.set()을 활용할 수 있다. 각 메서드들은 핸들러의 메서드, 인자와 동일하다.

const personProxy = new Proxy(person, {
  get: (obj, prop) => {
    console.log(`The vlue 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)
  },
})

Proxy는 객체의 동작을 커스터마이징할 수 있는 유용한 기능이다. Proxy는 유효성 검사, 포메팅, 알림, 디버깅 등 유용하게 사용된다.

핸들러 객체에서 Proxy를 너무 헤비하게 사용하면 앱의 성능에 부정적인 영향을 줄 수 있다. Proxy를 사용할 땐 성능 문제가 생기지 않을만한 코드를 사용해야 한다.

< 출처 : https://patterns-dev-kr.github.io/design-patterns/proxy-pattern/ >

profile
개발을 개발새발 열심히➰🐶

0개의 댓글