Chat-GPT4は有償らしいので、今のところ無償で利用できるMicrosoftのBing Chatを試してみました。
返ってきたソースコードは以下の通り。
using System;
using System.Collections;
// Aggregate
interface IAggregate
{
IIterator CreateIterator();
}
// Iterator
interface IIterator
{
bool HasNext();
object Next();
}
// ConcreteAggregate
class ConcreteAggregate : IAggregate
{
private ArrayList _items = new ArrayList();
public IIterator CreateIterator()
{
return new ConcreteIterator(this);
}
public int Count => _items.Count;
public object this[int index]
{
get => _items[index];
set => _items.Insert(index, value);
}
}
// ConcreteIterator
class ConcreteIterator : IIterator
{
private ConcreteAggregate _aggregate;
private int _current = 0;
public ConcreteIterator(ConcreteAggregate aggregate)
{
_aggregate = aggregate;
}
public bool HasNext()
{
return _current < _aggregate.Count;
}
public object Next()
{
if (HasNext())
{
return _aggregate[_current++];
}
else
{
throw new InvalidOperationException();
}
}
}
class Program
{
static void Main(string[] args)
{
var aggregate = new ConcreteAggregate();
aggregate[0] = "Item A";
aggregate[1] = "Item B";
aggregate[2] = "Item C";
var iterator = aggregate.CreateIterator();
while (iterator.HasNext())
{
Console.WriteLine(iterator.Next());
}
}
}
consoleで実行するコードのようなのでプロジェクトを作成し、ソースコードをコピーして実行してみる。
結果
Item A
Item B
Item C
結果が返ってきました。問題なく実行できるコードのようです。
GOFのデザインパターンはいつかは勉強しようかと思い書籍を買い込んでページを開くのですが、具体的に適用できる事例と遭遇することが無いと中々モチベーションが維持できず毎回挫折してしまいます。特にイテレータパターンは、多くの言語系の標準ライブラリに組み込まれており、構造を勉強することは大変価値があるとは思うのですが、個人的に使うことはまずないかなと思います。
今回Bing Chatが実行可能なサンプルコードを書いてくれたので中身を確認したいと思います。
Aggregate
インターフェイス
// Aggregate
interface IAggregate
{
IIterator CreateIterator();
}
IIterator
オブジェクトを生成するCreateIterator()
を定義しています。
インターフェイスですので継承して中身を実装することに成ります。
Iterator
インターフェイス
// Iterator
interface IIterator
{
bool HasNext();
object Next();
}
次の要素の有無を返すHasNext()
メソッド、現在の要素を返し次の要素へ移動するNext()
メソッドを定義しています。
ConcreteAggregate
クラス
// ConcreteAggregate
class ConcreteAggregate : IAggregate
{
private ArrayList _items = new ArrayList();
public IIterator CreateIterator()
{
return new ConcreteIterator(this);
}
public int Count => _items.Count;
public object this[int index]
{
get => _items[index];
set => _items.Insert(index, value);
}
}
Aggregate
を継承し実装するクラスになります。
private ArrayList _items = new ArrayList();
で配列をメンバーとして定義初期化しています。
ArrayListは初めて見ましたが、C#にテンプレートが導入される前から存在する可変長配列で要素の型はobject
のようです。要素を取り出して使う場合キャストが必須となります。List<string>
に置き換えることが出来そうです。置き換えるとイテレータパターンのサンプルにならないのでダメかもしれません。
public IIterator CreateIterator()
ではConcreteIterator
クラスのオブジェクトを生成して返しています。
public int Count => _items.Count;
_itemsの要素数を返します。
public object this[int index]
プロパティはindex
で指定した_items
の要素の読み書きをするプロパティ。プロパティを使っているあたりC#らしくて良いです。
ConcreteIterator
クラス
// ConcreteIterator
class ConcreteIterator : IIterator
{
private ConcreteAggregate _aggregate;
private int _current = 0;
public ConcreteIterator(ConcreteAggregate aggregate)
{
_aggregate = aggregate;
}
public bool HasNext()
{
return _current < _aggregate.Count;
}
public object Next()
{
if (HasNext())
{
return _aggregate[_current++];
}
else
{
throw new InvalidOperationException();
}
}
}
Iteratorの実装部分。
private int _current = 0;
で現在の要素のインデックスを保持しています。
HasNext()
はループの終了条件に使われます。
Next()
は_current
が指し示す_aggregate
の要素を返します。
この際_current
の値を加算することで次の要素に移動します。
_current++
で加算されますが、_aggregate
の要素にアクセスした後に処理されるようです。
Main()
これまで定義したクラスを組み合わせて、文字を格納した配列と、その要素に順番にアクセスするプログラムを実行しています。
ではこちらのパターンを実際使うかというと今のC#であればList<string>
とforeach()
の組み合わせで十分ですので、使うことはないかなと思います。(そういえば昔C言語で可変長配列を自前で作成する際、似たようなコードを書いた記憶があります。)
ただ、GOFのデザインパターンは用語としての意味を理解していると、文書生成AIにコード作成を依頼する際、「C#でGOFの〇〇〇パターンを使ったサンプルコードを書いてください。」のような使い方が出来て便利だと思いました。
コメント