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


関連記事

WebアプリからLINEのメッセージを送る方法

1 はじめに2 Messaging APIとは2.1 Messaging APIの仕組み2.2 Webhookイベント2.3 メッセージオブジェクトの種類2.4 料金形態3 LINE Develope ...

laravel logo

Laravelでメールを送る

1 はじめに1.1 準備2 実装2.1 Mailableクラスの作成2.2 テンプレートの作成2.3 Mailableクラスの修正2.4 コントローラの作成2.5 コンフィグの修正3 さいごに4 おす ...

WebアプリケーションにLINEログインを組み込む

1 はじめに2 LINEログインとは2.1 LINEログインでできること2.2 LINEログインのフロー3 LINEログインの設定3.1 プロバイダーを新規作成する3.2 チャネルを作成する3.3 リ ...

js

GoogleAppsScriptを使ってmBaaSの定期実行処理を実装する

1 はじめに1.1 簡単な状況説明1.2 定期実行を行う方法2 実装2.1 実装の流れ2.2 JavaScriptの実装2.3 スクリプトをアップロードする2.4 Google Apps Script ...

Go言語

Go言語のエラーハンドリングとログローテーション

1 はじめに2 エラーハンドリング2.1 error インターフェース2.2 pkg/errors パッケージ3 独自のエラータイプ付き errorsパッケージを作成4 log パッケージ4.1 lo ...

フォロー

blog-page_side_responsive

2024年2月
 123
45678910
11121314151617
18192021222324
2526272829  

アプリ情報

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