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


関連記事

crypto

公開鍵暗号の概要、用語と使用例

1 はじめに1.1 前提条件2 暗号化と復号2.1 暗号化とは2.2 復号とは3 暗号化方式3.1 共通鍵暗号3.2 公開鍵暗号4 署名と検証4.1 署名とは4.2 検証とは5 RSA暗号とは5.1 ...

Docker上のLaravelのログをFluentdに出力する

1 はじめに2 環境3 Fluentdについて4 目的5 Fluentd本体はdocker-composeで導入5.1 fluentd5.2 db5.3 app5.4 web6 Laravelからログ ...

Go言語

mutexを使ってGoで排他処理をする

1 はじめに1.1 mutexとは2 mutexを使った排他制御2.1 失敗するケース2.2 mutexを使って排他制御した場合2.3 構造体へmutexを埋め込む3 RWMutexを使う4 さいごに ...

rails

Railsの低レベルキャッシュを使ってみた

1 はじめに1.1 環境2 ドキュメント3 準備3.1 configの確認3.2 キャッシュストア4 使ってみる4.1 #read、#write、#delete4.2 #fetch4.3 オプション4 ...

laravel logo

Server-Side Eventsを触ってみた

1 はじめに2 Server-Side Events(SSE) とは3 実装してみる3.1 動作の流れ3.2 Laravel側3.3 React側4 Chat GPTのレスポンス5 さいごに6 おすす ...

フォロー

blog-page_side_responsive

2024年2月
 123
45678910
11121314151617
18192021222324
2526272829  

アプリ情報

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