Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

데코레이터 대 서브클래스

가장 최근 기사에서 Rails 5.1의 멋진 새 기능인 delegate_missing_to에 대해 언급했습니다. . delegate_missing_to 사용 , 한 개체에서 찾을 수 없는 모든 메서드는 대신 다른 개체에서 호출됩니다. :

class Player
  delegate_missing_to :@user

  def initalize(user)
    @user = user
  end

  def points
    Game.points_for_user(user.id)
  end
end

Player.new(user).name # calls user.name

그러나 Gavin이 주석에서 언급했듯이 이것은 상속을 피하는 이상한 방법처럼 보입니다. 왜 그냥 서브클래스를 사용하지 않습니까? 동일한 효과를 얻을 수 있으며 완전히 새로운 기능을 추가할 필요가 없습니다. 추가하는 것이 이상한 것 같습니다.

delegate_missing_to 이유가 있어야 합니다. 추가되었지만. 그리고 Rails 기능의 경우 pull 요청은 이러한 이유를 찾는 좋은 방법입니다. 이 풀 리퀘스트에서 DHH는 자신이 이 기능을 제안한 이유를 다음과 같이 언급했습니다.

<블록 인용>

데코레이터를 구축하려는 경우 일반적인 패턴은 다음과 같습니다.

발굴을 시작하기에 아주 좋은 장소인 것 같습니다.

데코레이터가 필요한 이유

데코레이터를 만들 때 새 하위 클래스를 만들지 않고 개체가 작동하는 방식을 변경하는 것입니다. 예를 들어 이전 코드에서:

class Player
  delegate_missing_to :@user

  def initalize(user)
    @user = user
  end

  def points
    Game.points_for_user(user.id)
  end
end

"플레이어가 장식 사용자'라는 이유로 플레이어가 거의 사용자처럼 작동하지만 points라는 추가 메서드가 있습니다. . 그리고 상속 없이 이 작업을 수행합니다.

왜 이런 것이 필요할까요? 대답하기 어려운 질문입니다. 많은 디자인 패턴과 마찬가지로 다른 패턴 대신 어디에 사용하고 싶은지 항상 명확하지 않기 때문입니다.

데코레이터를 언제 사용하시겠습니까?

데코레이터는 상속을 수행하는 더 복잡한 방법일 수 있습니다. 이 두 줄의 코드 중 어느 것이 더 낫습니까?

player = Player.new(User.new(name: "Justin")) # Player decorates User
player = Player.new(name: "Justin")           # Player subclasses User

분명히 두 번째 것입니다. 여기서 Player를 서브클래스 대신 데코레이터로 만드는 것은 코드 낭비일 뿐입니다.

하지만 나중에 개체를 만든 위치에서 멀리 떨어진 개체에 기능을 추가하려는 경우가 있습니다. 예를 들어, 다음과 같은 코드가 있다면 어떨까요?

user = User.find(1)

... some time later ...

player = Player.new(user)

이제 원하는 방법과 원하는 방식으로 사용자를 생성할 수 있습니다. User 객체를 생성하는 코드는 Player 클래스가 존재하는지조차 알지 못하거나 신경 쓰지 않습니다. 그리고 이러한 추가 메서드를 더 이상 원하지 않으면 원래 User 개체를 계속 사용할 수 있습니다.

이렇게 하면 행동을 다른 클래스로 구분하는 데 도움이 됩니다. 각 클래스는 플레이어, 직원, 개발자와 같은 특정 상황에서 User 개체가 어떻게 사용되는지에 초점을 맞출 수 있습니다. 상속을 사용하면 이 모든 것이 뒤죽박죽이 되기 쉽습니다.

MrChris는 댓글에서 데코레이터의 또 다른 이점을 언급했습니다.

개체를 장식할 때 해당 개체의 공용 메서드만 호출할 수 있습니다. 하위 클래스를 만들 때 모든 메서드를 호출할 수 있습니다(비공개 메서드도 포함). 이렇게 하면 하위 클래스가 실수로 부모의 구현 세부 정보에 의존할 수 있기 때문에 하위 클래스가 더 자주 중단될 수 있습니다. 이러한 세부 정보는 일반적으로 공개 방법보다 더 자주 변경됩니다.

데코레이터는 대규모 클래스를 나눌 때 특히 유용할 수 있습니다. 데코레이터를 사용하면 단일 책임 원칙을 더 쉽게 따를 수 있습니다. 각 데코레이터는 한 가지 일을 잘 할 수 있으며 데코레이터를 결합하여 더 복잡한 동작을 얻을 수 있습니다.

Ruby에서 동작을 공유하는 방법에는 여러 가지가 있습니다. 하위 클래스를 만들 수 있고 모듈을 결합할 수 있으며 원하는 경우 한 클래스에서 메서드를 가져와 다른 클래스에 연결할 수도 있습니다. 그러나 데코레이터 패턴은 약간 다른 것을 제공합니다. 객체 지향 언어의 구성 요소인 인스턴스 변수와 메서드 호출을 사용하고 있습니다. 이러한 기본 사항에서 앱이 실행되는 동안 코드를 지나치게 복잡하게 만들지 않고도 유연한 동작을 수행할 수 있습니다.