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

AASMGemを使用してRubyでステートマシンを作成する方法

今日は、ステートマシン、それらがどのように機能するか、AASMgemを使用したRubyプロジェクトでそれらを使用する方法について学習します。

信号機を想像してみてください…

赤、緑、黄色のいずれでもかまいません。

色が変わると、次へ 色は現在に基づいています 1つ。

AASMGemを使用してRubyでステートマシンを作成する方法

これは、目の不自由な人がいつ横断できるかを知るための音を出す種類だとしましょう。

あなたはこのためのソフトウェアを書いています。

毎回再生する音と次の色をどのように知るのですか?

次のようなifステートメントを記述できます:

if @light.state == "green"
  @light.play_green_sound
end

if @light.state == "green"
  @light.change_to_yellow
end

# ...

この状態チェックコードはいたるところにあります!

どうすればこれを改善できますか?

オブジェクト指向デザインの原則を適用すると、州のデザインパターンを再発見できます。

ステートデザインパターンとは何ですか?

ステートデザインパターンは、ステートマシンを実装する1つの方法です。

3つのコンポーネントが必要です

  • Context クラス、このクラスは現在の状態が何であるかを知っています
  • State クラス、このクラスは、個々の州によって実装されるべきメソッドを定義します
  • 州ごとに1つのクラス。これらのクラスは、Stateから継承します クラス

信号機の例では、コンテキストはTrafficLightです。

そして、状態はGreenRedYellow

すべての州が何をすべきかを知っています。

大きなメリット

すべての状態はそれ自体を知っているので、現在の状態をチェックする必要はありません。これは、条件文が少なくなり、複雑さの原因となることがよくあります。

信号機の実装

このパターンの実際の実装のコードを見てみましょう。

こちらがTrafficLightです :

class TrafficLight
  def initialize
    @state = nil
  end

  def next_state(klass = Green)
    @state = klass.new(self)

    @state.beep
    @state.start_timer
  end
end

これが基本のStateです :

class State
  def initialize(light)
    @light = light
  end

  def beep
  end

  def next_state
  end

  def start_timer
  end
end

はい、これら3つの方法は空です。

この「インターフェース」を定義することは、他のプログラミング言語(Javaなど)では一般的な規則ですが、Rubyでは一般的ではありません。

これはデモンストレーションの目的でここにあります。

ただし、initializeを共有したいのですが すべての状態がコンテキストを必要とするため、すべての状態間のメソッド (TrafficLight オブジェクト)状態の変化を通知する 。

3つの状態は互いに非常に似ているため、そのうちの1つだけのコードを示します。

これがGreenです 状態:

class Green < State
  def beep
    puts "Color is now green"
  end

  def next_state
    @light.next_state(Yellow)
  end

  def start_timer
    sleep 5; next_state
  end
end

すべての州は、次の州に切り替える方法と時期を知っています。

AIゲームの例

ステートマシンを使用して、RubyWarriorなどの現在の状態に依存するゲームを解決できます。

RubyWarriorでは、プレーヤーオブジェクトとボードが提供されます。

目標は

  • ボード上のすべての敵を倒します
  • HPを0より上に保ちながら出口に到達します

一度に1つの動きをすることができ、レベルを完了したい場合は適切な選択をする必要があります。

現在の状態を確認すると、その選択に役立ちます。

そのため、ステートマシンが優れたソリューションです。

ここに例があります

class Attacking < State
  def play(warrior)
    warrior.attack!

    @player.set_state(Healing) unless enemy_found?(warrior)
  end
end

これは、戦士がいる可能性のある状態の1つであり、敵が見えないときにHealingに移動します。 戦闘ダメージから回復する状態。

AASMGemの使用

遷移が有効であることを確認しながら現在の状態を追跡したい場合は、AASMのようなステートマシンの宝石を使用できます。

この宝石は、イベントのアイデアに基づいて構築されています (ライトスイッチを押すなど)トリガーが他の状態に移行します。

ここに例があります

require 'aasm'

class Light
  include AASM

  aasm do
    state :on, :off

    event :switch do
      transitions :from => :on, :to => :off, :if => :on?
      transitions :from => :off, :to => :on, :if => :off?
    end
  end
end

このクラスの使用方法

light = Light.new

p light.on?
# true

light.switch

p light.on?
# false

このステートマシンを使用すると、現在の状態が「オフ」の場合にのみ「オン」状態に移行できます。状態遷移中に特定のコードを実行するために、(前/後の)いくつかのコールバックを持つこともできます。

これらのコールバック 次のようなものを含めることができます:

  • メールの送信
  • 状態変化をログに記録する
  • ライブモニタリングダッシュボードの更新

さらに、AASMには、ActiveRecordを使用して現在の状態をデータベースに保存するオプションがあります。 。

AASMジェムビデオ

概要

ステートマシン、ステートデザインパターン、AASMジェムについて学びました。私のRubyニュースレター(7000人以上の購読者)を購読して、今すぐ学習を続けてください。新しい記事と購読者限定のRubyのヒントをお見逃しなく

今度は、これらの新しいアイデアを使って練習しましょう🙂

読んでくれてありがとう!


  1. Ruby Mapメソッドの使用方法(例付き)

    Mapは、配列、ハッシュ、範囲で使用できるRubyメソッドです。 マップの主な用途は、データを変換することです。 例 : 文字列の配列が与えられた場合、すべての文字列に目を通し、すべての文字を大文字にすることができます。 または、Userのリストがある場合 オブジェクト… 変換できます 対応するメールアドレス、電話番号、またはその他の属性のリストにそれらを追加します Userで定義 クラス。 これを行う方法を正確に見てみましょう! ルビーマップ構文 マップの構文は次のようになります: array = [a, b, c] array.map { |string| string.

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

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