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


関連記事

laravel logo

LaravelのFacade(ファサード)とは? 何気なく使用していた裏側の仕組みを解説!

1 はじめに1.1 Facadeを使用しているクラス2 Facadeの仕組み3 Facadeの作成3.1 サンプルコードに必要な実装3.2 Serviceの作成3.3 Facadeクラスの作成3.4 ...

Go言語

Go言語でテスト作成 testifyの基本的な使い方

1 はじめに2 Goテストフレームワークのスター数3 testifyについて3.1 testifyを導入する方法4 assartionについて4.1 assertion紹介4.2 ElementsMa ...

laravel logo

Laravel-debugerbarを使ってみた

1 はじめに2 インストール3 主な項目3.1 Messages3.2 Timeline3.3 Queries3.4 N+1 Queries3.5 Session3.6 Request4 さいごに5 ...

rails

Railsのバリデーション

1 はじめに2 基本的なバリデーション3 EachValidatorクラス4 Validatorクラス5 autoload_pathsの編集6 さいごに はじめに 今回はRailsのActiveRec ...

Go言語

goのcontextについて

1 はじめに2 contextとは2.1 contextの定義3 contextでキャンセルシグナルを伝達する3.1 cancel関数でキャンセルシグナルを伝達する3.2 キャンセルシグナルの伝達範囲 ...

フォロー

blog-page_side_responsive

2024年2月
 123
45678910
11121314151617
18192021222324
2526272829  

アプリ情報

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