はじめに
様々な言語で「デザインパターン」の本が世の中にありますが、筆者個人の経験では
いまいちピンとこない例
いまいちピンとこないコード
で説明されてることが多く、
結局これっていつ使うの?
という疑問に答えるには仕事仲間等との議論をしないと
辿り着けないことが多々ありました。
そこで特に「ゲーム開発ではどう使うか?」にフォーカスを当てて、実践的な例を交えて
デザインパターンの説明の需要があると思い記事を作りました。
デザインパターンを学ぶ理由
デザインパターンを学ぶ理由としては
- 車輪の再発明の防止
- 長文で読みにくいコード(可読性の低いコード)を減らす
- コードを疎結合にして変更に強くなる(変更時のコスト・変更箇所を減らす)
- モジュールとして使いまわせるように、コードの再利用性を高める
といった効果を期待できます。
対象読者
Unity 全くの初心者(インストールしただけで触ったことがないような方)はお断りです。
最低限以下のことは理解・経験を積んでおくことが必須になります。
- MonoBehaviour 継承クラスでコードを書いたことがある
- C# のピュアクラスを用いた自作クラスを作ったことがある
- クラスの継承という概念は知っている
そのため、脱・初心者
中級者へのステップアップ
として デザインパターンを学ぶ
のが良いと思います。
デザパタ記事リンク
生成系
構造系
様態・ふるまい系
- Chain of Responsibility パターン
- Command パターン
- Interpreter パターン
- Iterator パターン(本記事)
- Mediator パターン
- Memento パターン
- Observer パターン
- State パターン
- Strategy パターン
- TemplateMethod パターン
- Visitor パターン
Iterator パターンについて
反復子
という意味の Iterator
パターンですが、最近のプログラミング言語であれば必須の概念・デザインパターンです。
古くはC言語ではiterator という概念がなかったため、配列こそfor で回せますが、ポインターで次のノードを管理するような連結リストでは、for文ではなく、while等でしか回せません。
typedef struct node {
int item;
struct cell *next;
} Node;
// リスト
typedef struct {
Node *top;
} List;
const int N = 10;
int intArray[] ={1,1,2,3,5,8,13,21,34,55};
int i;
for(i=0; i<N; i++)
{
printf("%d\n", intArray[i]);
}
List *l = malloc(sizeof(List));
while( l != NULL){
printf("%d\n", l->item);
l=l->next;
}
このような状態では、ループ処理をしたくても、構造によって手法を変えなくてはなりません。
そこで iterator という概念を追加することで、対象が配列でも連結リストでも同じ方法で要素にアクセスできるようにします。
C# における Iterator パターン
C# ではiterator は IEnumerable
, IEnumerable<T>
, IEnumerator
, IEnumerator<T>
を返り値とします。
IEnumerator では MoveNext()
というメソッドを用いて次の要素にアクセスが可能です。
このメソッドは次の要素があればtrue, そうでなければfalseを返します。
つまり 以下のようにforeach とwhileが糖衣構文となります。
IEnumerator list;
foreach( var item in list)
{
print(item);
}
while(list.MoveNext())
{
print(list.Current);
}
また、C#のListでは public T this[int index] { get { throw null; } set { } }
のように、あたかも配列を操作しているようなオペレータを用意していますが、内部ではListの要素にアクセスできるように実装されています。
これも今度はListをforで回せるようにするためのiterator として機能が実装されています。
ゲームにおける Iterator
C#のコードを書くときにあまりにも当たり前に使われています。
QueueやStackやDictionaryをforeachで回して全件探索したりなど、初心者エンジニアでもごくごく当たり前にコードを書いていると思います。
まとめ
モダンな言語では当たり前になっているiteratorですが、過去の言語との比較や、実際にどう実装しているのかをみるだけでも非常に学ぶ価値があります。
また、実装方法を確認することによって、 本質を学べたり、何故 for よりforeachのほうがパフォーマンスが落ちる場合があるのか?など実装上のパフォーマンスチューニングにつながるような知見も得られたりするので、このような当たり前になっていることでも積極的に学ぶと良いでしょう。