Proxy 패턴
대상 객체에 대하여 읽기 및 쓰기를 직접 제어한다
📜 원문: patterns.dev - proxy pattern
📜번역 : https://patterns-dev-kr.github.io/design-patterns/introduction/
Proxy 객체를 활용하면 특정 객체와의 인터렉션을 조금 더 컨트롤 할 수 있게 됩니다.
Proxy 객체는 어떤 객체의 값을 설정하거나 값을 조회할때 등의 인터렉션을 직접 제어할 수 있습니다.
일반적으로 Proxy는 어떤 이의 대리인을 뜻합니다.
그 사람과 직접이야기하는 것 대신. 이야기를 원하는 사람의 대리인에게 이야기하는것이죠.
JavaScript에서도 해당 객체를 직접 다루는 것이 아니고 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 클래스의 두 번째 인자는 핸들러를 의미합니다. 핸들러 객체에서 우리는 인터렉션의 종류에 따른 특정 동작들을 정의할 수 있습니다. 또한 여러 메서드들을 추가할 수 있는데. 일반적으로 아래에 설명하는 get 과 set 입니다.
- get : 프로퍼티에 접근하려고 할 때 실행된다.
- set : 프로퍼티에 값을 수정하려고 할 때 실행된다.
결과적으로 다음 동작이 수행됩니다.
person 객체와 직접 인터렉션하는 것 대신 personProxy 객체와 인터렉션하게 됩니다.
personProxy 객체에 핸들러를 추가해 보자. 프로퍼티를 수정하려 할 때는. 앞서 말한 것과 같이 Proxy 의 set 메서드가 호출되므로 이 핸들러 안에서 변경 전의 값과 변경 후의 값을 콘솔로 확인할 수 있습니다.
프로퍼티의 값을 읽으려 할 때는 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
},
})
아래 예제를 통해 값을 수정할 때와 읽을 때 어떻게 동작하는지 확인해 보죠.
결과
name 프로퍼티에 접근하려 할 때. Proxy 객체가 콘솔에 값을 출력해 줍니다: The value of name is John Doe
age 프로퍼티를 수정하려고 할 땐. Proxy 객체가 변경 이전 값과 이후의 값을 콘솔에 출력합니다: Changed age from 42 to 43
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 ${obj[prop]} to ${value}.`)
obj[prop] = value
}
},
})
다음 예제에서 유효하지 않은 값들을 넣어봄으로써 테스트해볼 수 있습니다.
결과
Proxy는 person객체를 실수로 수정하는것을 예방해주어 데이터를 안전하게 관리할 수 있습니다.
Reflect
JavaScript는 Reflect라는 빌트인 객체를 제공하는데 Proxy와 함께 사용하면 대상 객체를 쉽게 조작할 수 있습니다.
이전 예제에서는 Proxy의 핸들러 내에서 괄호 표기를 사용하여 직접 프로퍼티를 수정하거나 읽을 수 있었습니다.
그 대신에 Reflect 객체를 쓸 수 있습니다. Reflect 객체의 메서드는 핸들러 객체과 같은 이름의 메서드를 가질 수 있습니다.
obj[prop] 형태로 프로퍼티에 직접 접근하거나 obj[prop] = value 형태의 코드로 값을 수정하는 대신, Reflect.get() 혹은 Reflect.set() 을 활용할 수 있습니다. 각 메서드들은 핸들러의 메서드와 인자 또한 동일합니다.
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}`)
Reflect.set(obj, prop, value)
},
})
이제 대상 객체의 값을 읽거나 수정할 때 Reflect 객체를 활용할 수 있게 되었습니다.
Proxy는 객체의 동작을 커스터마이징할 수 있는 유용한 기능입니다. Proxy는 유효성 검사, 포메팅, 알림, 디버깅 등 유용하게 사용됩니다.
핸들러 객체에서 Proxy 를 너무 헤비하게 사용하면 앱의 성능에 부정적인 영향을 줄 수 있습니다.
Proxy를 사용할 땐 성능문제가 생기지 않을 만한 코드를 사용하도록 합시다.
참조
- Proxy - MDN
- JavaScript Proxy - David Walsh
- Awesome ES2015 Proxy - GitHub @mikaelbr
- Thoughts on ES6 Proxies Performance - Valeri Karpov
'프로그래밍(Basic) > 디자인 패턴(JS)' 카테고리의 다른 글
[바미] Container/Presentational 패턴 (0) | 2022.09.15 |
---|---|
[바미] Prototype 패턴 (0) | 2022.09.14 |
[바미] Provider 패턴 (0) | 2022.09.13 |
[바미] Singleton 패턴 (0) | 2022.09.02 |
[바미] Design Pattern 소개 (0) | 2022.08.31 |