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

Ruby에서 Case 문 사용 중지

OOP(객체 지향 프로그래밍)의 모든 기능을 사용하고 있습니까, 아니면 놓치고 있습니까?

객체 유형에 따라 결정을 내리는 경우 중요한 OOP 기능인 다형성을 놓치게 됩니다.

유형 결정은 일반적으로 case 문(OO 친화적이지 않음) 내에서 이루어지며 이 기사에서는 이를 제거하여 더 나은 코드를 작성하는 방법을 배웁니다.

유형 확인

먼저 다형성을 활용하지 않는 예를 보여드리겠습니다.

우리는 "바위, 종이, 가위" 게임을 구현하고 하나의 Game을 만들기로 결정했습니다. 가능한 모든 이동에 대해 클래스 및 하나의 클래스.

승자를 확인하기 위해 play를 구현할 것입니다. Game의 메소드 :

class Game
  def self.play(move1, move2)
    return :tie if move1 == move2

    move1.wins_against?(move2)
  end
end

다음은 동작 중 하나입니다(다른 동작은 동일한 패턴을 따릅니다).

class Rock
  def wins_against?(other_move)
    case other_move
    when Paper then false
    when Scissors then true
    end
  end
end

이제 play를 호출할 수 있습니다. 두 번의 이동이 있는 방법으로 첫 번째 이동이 이기면 알 수 있습니다.

p Game.play(Rock.new, Paper.new)
# false

좋습니다. 작동하지만 더 잘할 수 있습니까? 그 추악한 사례 진술을 제거할 수 있습니까?

유형 검사 대신 다형성

예! OOP 기초를 사용하여 유형 검사 case 문을 제거할 수 있습니다.

아이디어는 현재 클래스를 알고 있다는 사실을 사용하여 다른 이동 개체가 우리를 이길 수 있는지 묻는 것입니다.

그리고 우리는 클래스에 특정한 메서드 이름을 사용할 것입니다(Rock 메소드 이름은 do_you_beat_rock?일 수 있습니다. )

<블록 인용>

Ruby에서 다형성은 객체의 클래스를 확인하지 않고도 모든 메서드 호출(OOP 용어로 메시지라고도 함)을 객체로 보내는 기능입니다. 이것은 "오리 타이핑"이라고도 알려져 있지만 그 용어를 좋아하지 않습니다 🙂

자바에는(잠시만요...) "인터페이스"라는 것이 있어서 컴파일러 수준에서 클래스에 의해 구현되도록 강제하는 메서드 집합을 허용합니다.

Ruby에는 그런 기능이 없으므로(아마도 더 나은 방법으로) 테스트에 의존해야 합니다.

이 새로운 구현의 코드 예를 살펴보겠습니다.

class Rock
  def wins_against?(other_move)
    other_move.do_you_beat_rock?
  end

  def do_you_beat_paper?
    false
  end

  def do_you_beat_scissors?
    true
  end
end

사례 진술이 어떻게 사라졌는지 주목하십시오. 단일 메서드 호출과 두 개의 메서드 정의로 대체되었습니다.

<블록 인용>

업데이트 :몇몇 독자들이 논평했듯이, 나는 이 패턴을 구현할 때 논리가 역전된다는 것을 눈치채지 못했다. Daniel P. Clark이 제안한 솔루션 중 하나는 play에서 순서를 뒤집는 것입니다. move2.wins_against?(move1) 메소드 .

이게 훨씬 깔끔하지 않나요? 어떻게 생각하세요?

한 번 더!

이제 새로운 움직임을 추가하고 싶다고 가정해 보겠습니다. 무엇을 변경해야 합니까?

잠시 생각해 보세요...

case 문 접근 방식을 사용하면 모든 이동에 새 분기를 추가해야 합니다. 새로운 기능을 도입하기 위해 완벽하게 작동하는 방법을 변경해야 하는 "강요"에 유의하십시오.

하지만 우리의 OOP 지향적인 버전에서는 문제가 되지 않습니다. 새로운 메소드를 추가하기만 하면 됩니다. 이것이 실행 중인 개방/폐쇄 원칙(SOLID의 "O")입니다.

또 다른 옵션은 메타프로그래밍을 사용하는 것입니다(method_missing 또는 define_method ).

실제로 이를 위해 메타프로그래밍을 사용할까요?

이동 횟수가 지속적으로 변경되거나 이동 수가 많은 경우가 아니면 그렇지 않을 것입니다.

메타프로그래밍에는 대가가 있습니다. 일부 사람들이 믿는 것처럼 만병통치약이 아닙니다. 약간의 유연성을 위해 성능과 가독성을 거래할 수 있습니다.

결론

이 문서에서는 클래스 유형을 확인하기 위해 case 문을 사용하는 것을 피해야 함을 배웠습니다. . 대신 다형성을 활용해야 합니다. .

이렇게 하면 기존 코드를 변경하는 대신 새 코드를 추가하여 확장할 수 있는 더 나은 코드를 만드는 데 도움이 됩니다. 이제 조치를 취하고 리팩토링을 할 차례입니다 🙂

Btw 이것이 내가 귀하의 도구 상자에서 case 문을 완전히 제거하도록 옹호한다는 것을 의미하지는 않지만, 작성하는 자신을 발견할 때마다 조심해야 합니다. 그것이 문제에 대한 최선의 해결책인지 확인하십시오.

이 기사를 공유하는 것을 잊지 마세요. 내가 이런 기사를 계속 쓰기를 원하신다면!