Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

RubyでのCaseステートメントの使用を停止する

OOP(オブジェクト指向プログラミング)の全機能を使用していますか、それとも見逃していますか?

オブジェクトのタイプに基づいて決定を下している場合、1つの重要なOOP機能であるポリモーフィズムを見逃しています。

タイプの決定は通常、caseステートメント(OOに対応していない)内で行われます。この記事では、それらを削除してより適切なコードを作成する方法を学習します。

タイプの確認

まず、ポリモーフィズムを利用しない例を示します。

「じゃんけん」ゲームを実装したいので、1つのGameを用意することにしました。 クラスと可能な移動ごとに1つのクラス。

勝者を確認するために、playを実装します Gameのメソッド :

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

    move1.wins_against?(move2)
  end
end

そして、これが動きの1つです(他は同じパターンに従います):

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

これで、playを呼び出すことができます 2つの動きを伴う方法で、最初の動きが勝つかどうかがわかります。

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

わかりました、これは機能していますが、もっとうまくできるでしょうか?その醜いcaseステートメントを取り除くことはできますか?

型チェックの代わりにポリモーフィズム

はい! OOPの基礎を使用することで、型チェックのcaseステートメントを取り除くことができます。

アイデアは、現在のクラスを知っているという事実を使用して、他の移動オブジェクトが私たちを打ち負かすことができるかどうかを尋ねることです。

そして、クラスに固有のメソッド名を使用します(Rockの場合) メソッド名は次のようになります:do_you_beat_rock?

Rubyでは、ポリモーフィズムとは、オブジェクトのクラスをチェックすることなく、任意のメソッド呼び出し(OOP用語ではメッセージとも呼ばれます)を任意のオブジェクトに送信する機能です。これは「ダックタイピング」とも呼ばれますが、私はその用語が好きではありません🙂

Javaでは(ちょっと待ってください…)、コンパイラレベルでクラスによって一連のメソッドを強制的に実装できるようにする「インターフェイス」と呼ばれるものがあります。

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

caseステートメントがなくなっていることに注目してください。 1つのメソッド呼び出しと2つのメソッド定義に置き換えられました。

更新 :一部の読者がコメントしているように、このパターンを実装するときにロジックが逆になっていることに気づきませんでした。ダニエルP.クラークが提案した解決策の1つは、playで順序を入れ替えるだけです。 move2.wins_against?(move1)へのメソッド 。

これはもっときれいではないですか?どう思いますか?

もう1つの動き!

ここで、新しい動きを追加したいとします。何を変更する必要がありますか?

ちょっと考えてみてください…

caseステートメントのアプローチでは、すべての動きに新しいブランチを追加する必要があります。新しい機能を導入するために、完全に機能する方法を変更するように「強制」されていることに注意してください。

しかし、それは私たちのよりOOP指向のバージョンでは問題ではありません。新しいメソッドを追加するだけです。これは、実際のオープン/クローズド原則(SOLIDの「O」)です。

別のオプションは、メタプログラミングを使用することです(method_missingを使用) またはdefine_method

これに実際にメタプログラミングを使用しますか?

動きの数が絶えず変化している場合、または動きの数が多い場合を除いて、おそらくそうではありません。

メタプログラミングにはコストがかかります。一部の人が信じているような特効薬ではありません。パフォーマンスと読みやすさを少し柔軟性のあるものと交換します。

結論

この記事では、caseステートメントを使用してクラスタイプをチェックすることは避けてくださいことを学びました。 。代わりに、ポリモーフィズムを利用する必要があります 。

これは、既存のコードを変更する代わりに新しいコードを追加することで拡張できる、より優れたコードを作成するのに役立ちます。今度はあなたが行動を起こし、リファクタリングを行う番です🙂

ところで、これは私がツールボックスからケースステートメントを完全に取り除くことを提唱しているという意味ではありませんが、自分でケースステートメントを書いていることに気付いたときは常に注意する必要があります。それが問題の最善の解決策であることを確認してください。

この記事を共有することを忘れないでください このような記事を書き続けてほしいのなら!


  1. Rubyのケースステートメントの多くの用途

    if / elsifを使用する必要があるときはいつでも 代わりにRubyのcaseステートメントを使用することを検討できるステートメント。この投稿では、いくつかの異なるユースケースと、それが実際に内部でどのように機能するかを学びます。 注:他のプログラミング言語では、これはスイッチとして知られています。 ステートメント。 Rubyのcaseステートメントのコンポーネント: キーワード 説明 ケース ケースステートメントの定義を開始します。使用する変数を取得します。 いつ 一致する可能性のあるすべての条件は1つのwhenステートメントです。 その他 一致

  2. Rubyの配列クラスの使用方法(例+便利なメソッド)

    アレイとは何ですか? 配列は組み込みのRubyクラスであり、0個以上のアイテムのリストを保持します 、およびこれらすべてのアイテムを簡単に追加、アクセス、およびループするのに役立つメソッドが含まれています。 配列が存在しない場合は多くの変数を使用する必要があるため、これは便利です。 例 : a =1b =2c =3 しかし、代わりに、あなたはそうすることができます : 番号=[1、2、3] 最良の部分は? 配列内には何でも入れることができます! いいね : 数字 文字列 より多くのアレイ! (それは多次元配列になります) アレイを最大限に活用できるように、アレイについ