라떼군 이야기


4 / 13강

데코레이터: 기능을 감싸서 더하기

문자열을 저장하는 객체에 기록 기능을 더하고 싶습니다. 원래 저장 객체를 고치거나 저장 방식마다 하위 클래스를 만들지 않고, 같은 메서드를 제공하는 객체로 감쌀 수 있습니다.

호출을 감싼 뒤 원래 객체에 전달합니다

class MemoryStore:
    def __init__(self):
        self.items = []
    def write(self, text):
        self.items.append(text)

class LoggedStore:
    def __init__(self, inner):
        self.inner = inner
    def write(self, text):
        print("write:", text)
        self.inner.write(text)

store = MemoryStore()
LoggedStore(store).write("hello")
print(store.items)

write: hello를 출력한 뒤 저장된 ['hello']를 보여 줍니다. LoggedStore도 MemoryStore처럼 write(text)를 제공합니다. 호출하는 쪽은 저장 객체가 기록 계층에 감싸여 있는지 몰라도 됩니다.

압축과 암호화처럼 여러 기능을 겹쳐 감쌀 수도 있습니다. 다만 순서가 결과에 영향을 줍니다. 먼저 압축한 뒤 암호화하는 것과 반대 순서는 같은 작업이 아닙니다. 감싼 계층이 많으면 오류가 어디서 났는지 추적하기도 어려워집니다.

Python의 @ 문법과는 구분합니다

Python 데코레이터는 함수나 클래스를 받아 다른 값으로 바꾸는 문법과 기능입니다. 객체를 같은 인터페이스로 감싸는 설계패턴을 구현하는 데 활용할 수 있지만, 두 개념이 항상 같은 것은 아닙니다. 여기서는 일반 객체의 구성으로 패턴을 보여 줍니다.

확인 문제

감싸는 객체의 메서드 이름을 save_with_log로 바꾸면 기존 호출 코드를 그대로 쓸 수 있을까요?

해설 보기

기존 코드가 write를 호출한다면 그대로 교체할 수 없습니다. 데코레이터의 핵심은 사용하는 쪽이 기대하는 인터페이스와 동작의 약속을 유지하면서 기능을 추가하는 것입니다.

제품 기획, 개발 파트너 찾으시나요? 개인, 팀, 기업 모두 환영. 문제 정의부터 출시까지 함께합니다.