ohashi
2021/03/09 (火) 16:52:34
「ポーリング(監視)型」vs「コールバック型」の問題ですかね
今回の例では「監視したい人(A)」と「監視される人(B)」が1対1の単純な関係性なので「AがBを毎フレーム監視する」という実装が一番シンプルになりそうですね。
Aの数が動的に変化するような場合は「コールバック型」を使います。その際「オブザーバーパターン」を適用することが多いです。
今回挙げられた例で避けたい設計は「Bが終了したことをAに伝える時、BがAの関数を呼び出す」という形です。この形にすると「BはAに依存する」ことになり「BはAなしには存在できない」ことになります。
自分が設計を行う際に最も気をつけていることの1つが「依存関係をシンプルにする」ということで、これを設計の指針にしていますね。仮に全体の実装が複雑になってしまう場合でも「依存関係をシンプルにする」ことを常に心がけています。
通報 ...
ポーリング型、コールバック型、オブザーバーパターン、いろいろ勉強になります。
仮にBが終了したことをAに伝える形にする場合、どういう方法にすると独立性を保てるのでしょうか?
>仮にBが終了したことをAに伝える形にする場合、どういう方法にすると独立性を保てるのでしょうか?
「Bが終了したら呼び出される関数」をBに登録できるようにして、Bは終了時に登録されている関数を呼び出す、という形で実現できます。Bは誰に何の関数を登録されたのか知りません。終了時にただ機械的に登録された関数を呼び出すだけです。この設計にすることでBはAの存在を知ることなく終了したことを知りたい人に伝えることが出来ます。
C/C++では関数ポインタやファンクタ、C#ではデリゲート等で実装できます。
(GMSは触ったことがないので実現方法が分かりません、、、ごめんなさい、、、)
私が最初のポストで挙げた「コールバック型」というのはまさに上記のような実装のことです。特定のタイミングで呼び出してもらいたい関数を登録する設計です。
GMSは関数への参照idを変数に入れたり、それを他の関数に渡したり渡された関数を実行したりできるので、それが該当するようです(GMSでの呼び方はよく分かりません)。
例えば、
Aが「歩く」のあとでBに演出表示をさせて「止まって」待機し、Bが完了したタイミングで「ジャンプ」に移る場合は、Aの「ジャンプする」の部分を関数jumpとして切り出しておいて、AがBに指示を出す時点で関数jumpを渡す(=コールバック関数)。Bは自分の処理が終わったら渡されてるA関数jumpを実行。その結果、Aはジャンプすると。
イメージ的にはAはBに「ジャンプ」の動きを移譲し、ぼーっと待機。Bは自分の処理を終えて関数jumpを呼び出し。Aは遠隔で操られ動かされる感じでしょうか(全然違うかもしれませんが)。
関数jumpがどうやってAを参照し動かすのかですが、たぶん上記のコードのように、Aがコールバック関数を渡す時に自分のidを一緒に渡しておけば下記のようにBはwith構文で実行できるのでこれで対処できそうです。
これでBはAが誰だろうと知ったこっちゃなく何をするのかも知ったこっちゃなく済みます(と思います…)
教えていただいたキーワードでいろいろ調べてみようと思います。ありがとうございます。