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


関連記事

新時代のPythonプロジェクト・パッケージ管理ツール「Rye」使ってみた

1 はじめに2 Ryeとは?3 Ryeを使ってみる3.1 Ryeのセットアップ3.2 仮想環境に入る3.3 依存パッケージの追加4 VSCodeから使ってみる5 さいごに6 おすすめ書籍 はじめに P ...

rails

Rails Developer Meetup に参加してきました【2日目】

1 はじめに2 Rails Developer Meetup3 テストのないレガシーなRailsアプリをリファクタした話3.1 なぜリファクタリングしたのか3.2 コードを3種類に分類する3.3 モデ ...

laravel logo

Laravelでの署名付きURL生成

1 はじめに2 今回のサンプル3 ビュー4 ルーティング5 コントローラー5.1 署名付きURLの生成5.2 期限ありの署名付きURLの生成5.3 署名のチェック6 おまけ6.1 署名の仕組7 さいご ...

laravel logo

LaravelでHTTP通信

1 はじめに2 インストール3 基本的な使い方3.1 GETでリクエストを投げる3.2 リクエストヘッダーを指定3.3 クエリパラメータを指定3.4 timeout時間を指定3.5 POSTでリクエス ...

laravel logo

[Laravel] ログの扱い方 [5.8]

1 はじめに2 環境3 Monologについて4 コード上で設定する方法5 config/logging.phpで設定する方法6 おまけ:ログレベルについて7 さいごに8 おすすめ書籍 はじめに こん ...

フォロー

blog-page_side_responsive

2024年2月
 123
45678910
11121314151617
18192021222324
2526272829  

アプリ情報

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