Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

Ruby 데코레이터(Decorator) 디자인 패턴 완벽 가이드

데코레이터 디자인 패턴이란 무엇일까요? 그리고 Ruby 프로젝트에서 이 패턴을 어떻게 활용할 수 있을까요?

데코레이터 디자인 패턴은 클래스 자체를 수정하지 않고도 객체에 새로운 기능을 추가할 수 있게 해주는 디자인 패턴입니다.

실제 예제를 통해 살펴보겠습니다!

로깅과 성능 측정 예제

이 예제에서는 rest-client 같은 gem을 사용해 HTTP 요청을 보내는 상황을 가정해 봅시다.

require 'restclient'

data = RestClient.get("www.rubyguides.com")

이제 일부 요청에 로깅 기능을 추가하고 싶지만, RestClient 모듈 자체는 건드리고 싶지 않다고 가정해 보겠습니다.

바로 이럴 때 데코레이터 패턴이 빛을 발합니다.

로깅 모듈은 다음과 같이 작성할 수 있습니다:

module LogHTTPRequest
  def get(url)
    puts "Sending Request For #{url}"
    super
  end
end

이 모듈은 원하는 정보를 화면에 출력한 뒤, super를 통해 RestClient의 원래 get 메서드를 그대로 호출합니다.

요청 객체에 로깅 기능을 붙이려면 extend 메서드를 활용하면 됩니다.

실제 사용 예시입니다:

class HTTPClient
  def initialize(client = RestClient)
    @client = client
  end

  def get(*args)
    @client.get(*args)
  end
end

client = HTTPClient.new
client.extend(LogHTTPRequest)

client.get("rubyguides.com")

여기서 HTTPClient라는 래퍼(wrapper) 클래스를 만든 이유는, RestClient가 모듈이기 때문입니다. Ruby에서는 모듈로부터 직접 객체를 생성할 수 없습니다.

데코레이터 패턴을 언제 사용해야 할까?

이 패턴의 가장 큰 매력은 단 하나의 객체만 향상시킨다는 점입니다. 덕분에 로깅 기능이 없는 클라이언트와 로깅 기능이 있는 클라이언트를 자유롭게 선택해서 사용할 수 있습니다.

또한 데코레이터는 여러 겹으로 쌓아 올릴 수 있습니다. 성능 측정 전용 데코레이터, 로깅 전용 데코레이터 등을 필요에 따라 조합하는 것이 가능합니다.

만약 상속을 사용해 HTTPClientWithLogging, HTTPClientWithPerformanceTesting 같은 클래스를 만들었다면 이러한 조합은 불가능했을 것입니다.

Ruby 데코레이터(Decorator) 디자인 패턴 완벽 가이드

WithLoggingWithPerformanceTesting을 동시에 적용하려면 결국 아래처럼 새로운 클래스를 만들어야 합니다...

class HTTPClientWithLoggingAndPerformanceTesting
  # ...
end

데코레이터 패턴은 코드 중복과 어색하고 긴 클래스 이름을 피하면서 이 문제를 우아하게 해결해 줍니다.

마무리 정리

이번 글에서는 데코레이터 디자인 패턴에 대해 배웠습니다. 이 패턴을 활용하면 클래스를 변경하지 않고도 객체에 새로운 기능을 유연하게 추가할 수 있습니다.

읽기만 하지 마세요! 직접 코드를 작성하며 이 개념을 연습하고 적용해 보세요. 실전 경험이 쌓이면 실제로 필요한 순간에 바로 떠올릴 수 있습니다.

더 많은 개발자가 이 글을 볼 수 있도록 공유 부탁드립니다 🙂