BackEnd

FSMを使った状態管理をGoで実装する

投稿日:2024年2月5日 更新日:

はじめに

一般的なアプリケーションには、少なからず、何らかの状態変化を管理するコードが含まれていると思います。

それが、管理する状態が少なかったり簡単である場合は、 if や case を使って処理すれば良いですが、状態が多岐にわたり、状態遷移に制限があるような場合だと、途端に煩雑になってしまいます。

そのような状態管理をするには、FSM(finite state machine)を使うと、状態管理を簡潔明瞭に書くことができます。

今回は、GoでFSMを使った状態管理を実装してみます。

FSMとは

FSM(finite state machine)とは、有限状態機械、または、有限オートマトンなどと言われる、状態管理に用いられるモデルのことです。

このモデルは、有限個の状態(States)と遷移(Transitions)の動作を含み、状態の移行はイベントによって行われます。

FSMについてもっと詳しく知りたい方は、こちら等をご覧ください。

基本的な実装

FSMを実装するに当たり、looplab/fsm ライブラリを使用します。

実装する状態管理の概要

状態管理を実装する題材として、架空の横スクロールゲームを例に実装を行います。

このゲームには以下の状態があります。

  • Standing(静止中)
  • Walking(歩行中)
  • Running(走行中)
  • Jumping(ジャンプ中)
  • Attacking(攻撃中)

これらの状態は、それぞれ以下の状態に遷移させることができます。

to Standing to Walking to Running to Jumping to Attacking
from Standing NG OK OK OK OK
from Walking OK NG OK OK OK
from Running OK OK NG OK OK
from Jumping OK NG NG NG OK
from Attacking OK OK OK OK OK

状態管理を実装する

これをコードで表現すると、以下のようになります。

順番にコードを見ていきます。

まず初めに、FSMにどんな状態があり、どの状態に遷移できるかを設定します。

ここで設定するNameはイベント名、Srcはどの状態からの遷移を許可するか、Dstは遷移先の状態を表しています。

現在の状態は、 Current() メソッドで取得することができます。

Event() メソッドを使って状態を変化させることができます。

ただし、JumpingからRunningのような許可されていない状態遷移を行うと、エラーが発生します。

基本的にはこれだけで状態管理を行うことができます。

次の項では、より実践的なFSMの実装を行っていきます。

structを定義した応用的な実装

先程の実装では、単に状態を遷移させただけで、状態管理を行う対象がありませんでした。

この項では、Character構造体を定義して、Characterの状態管理を行います。

サンプルコードは以下のとおりです。

先程のコードからの変更点としては、まず、Character構造体を定義し、非公開のフィールドとしてFSMを持つようにしました。

次に、 New() 関数でCharacterを生成するようにして、FSMのコールバックを登録しました。

fsm.Callbaks のKeyに enter_attaking を指定していますが、これは prefix_event の形式にする必要があります。

prefixとして指定できるものは以下のとおりです。

  • before
  • leave
  • enter
  • after

それぞれが実行されるタイミングに該当しています。

Character構造体の状態遷移は外部から行えないように隠蔽しています。

大体は、この様にFSMを内部に隠蔽する形になるのではないかと思います。

FSMの可視化

設定したFSMの状態遷移図を様々なフォーマットで出力することができます。

上記の様にフォーマットとして graphviz を指定すると、このような出力がされます。

これを http://www.webgraphviz.com/ で可視化したものがこちらです。

states

 

graphviz 以外のフォーマットでも出力することができます。

さいごに

サンプルの状態管理はシンプルなものでしたが、実際のアプリケーションではより複雑な制御が求められることが多々あると思いますので、その際にFSMの真価が発揮されるのではないでしょうか。

おすすめ書籍

Go言語 100Tips ありがちなミスを把握し、実装を最適化する impress top gearシリーズ Go言語プログラミングエッセンス エンジニア選書 初めてのGo言語 ―他言語プログラマーのためのイディオマティックGo実践ガイド

blog-page_footer_336




blog-page_footer_336




-BackEnd
-

執筆者:

免責事項

このブログは、記事上部に記載のある投稿日時点の一般的な情報を提供するものであり、投資等の勧誘・法的・税務上の助言を提供するものではありません。仮想通貨の投資・損益計算は複雑であり、個々の取引状況や法律の変更によって異なる可能性があります。ブログに記載された情報は参考程度のものであり、特定の状況に基づいた行動の決定には専門家の助言を求めることをお勧めします。当ブログの情報に基づいた行動に関連して生じた損失やリスクについて、筆者は責任を負いかねます。最新の法律や税務情報を確認し、必要に応じて専門家に相談することをお勧めします。


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連記事

icon

PHP、Ruby、Pythonのfor構文を比較してみた

1 はじめに1.1 環境2 ドキュメント2.1 PHP2.2 Ruby2.3 Python3 1から100まで出力してみる3.1 PHP3.2 Ruby3.3 Python4 リスト型(配列)の出力4 ...

Go言語

Go言語 gocraft/workを使って常駐プロセスでジョブを処理させる

1 はじめに2 workの特徴3 workを使えるようにする3.1 Redisのインストール3.2 Go用のライブラリインストール4 Enqueue〜ジョブ実行まで4.1 Enqueue側4.2 ジョ ...

軽量なAlpine Linuxイメージでgitbookのローカル環境を構築する

1 はじめに2 Alpine Linuxとは3 Docker本体のインストール4 サンプルリポジトリのダウンロード5 dockerイメージ作成6 Gitbook初期化&実行7 Dockerの ...

Next.jsのrevalidatePathとrevalidateTag

1 はじめに2 前提3 revalidatePathとrevalidateTag3.1 revalidatePath3.2 revalidateTag4 今回の場合5 おすすめ書籍 はじめに Next ...

Go言語

Go 1.18のWorkspacesモードでマルチモジュール化

1 はじめに2 マルチモジュール構成2.1 非Workspacesモードの場合2.2 Workspacesモードの場合3 go workコマンド3.1 init3.2 edit3.3 sync3.4 ...

フォロー

blog-page_side_responsive

2024年2月
 123
45678910
11121314151617
18192021222324
2526272829  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。