俺カスタムなイテレータ (4)
2008/09/02 21:16 - デザインパターン
マイ・カスタム・イテレータの続き。
今回は AqCollection と AqIterator のパブリックメソッドを中心とした話。
オブジェクト指向の特徴のひとつとして機能を隠蔽することでユーザに優しくなるというのがあります。
今までコードを組むときには、あまりそういったことを意識せずに書き流してきましたが、今は反省しています。 今後はそういった部分にも意識的でいようと思います。
オブジェクトを格納するコレクションと、それを走査するイテレータの協同がイテレータパターンなわけですが、今回、そのオブジェクト思考の思想に則っていろいろ考慮した結果、イテレータパターンを使用する際の二つのクラスの関係は、イテレータが主でありコレクションは従ということを意識しながら設計をおこなったつもりです。
ところで前回アップしたクラスファイルのうち、AqIterator と AqCollenction にさっそく差し替えが発生しました。
今回はその差し替えたクラスを基に説明をおこないます。
AqCollection
コレクションの機能は極力削り、public なメソッドは、以下の二つだけ。
- add(obj:Object)
- オブジェクトの格納
- 実装はコレクション内部の Array への push()
- iterator():AqIterator
- イテレータの生成
- 1回だけしか実行できない
public なプロパティは無し。
length と lock という、外部からアクセスできるようにしなければいけないプロパティが存在します。 でもちょっと考えたら、それらは AqIterator だけがアクセスできればよいので public ではなく internal とし、AqCollection と AqIterator は同じパッケージに所属させることにしました。
で、AqIterator から AqCollenction の length と lock へのアクセスは、AqIterator に隠蔽します。
思えば internal という属性を初めて知ったとき、同じパッケージ内からの参照だけ有効なんてスコープにどんな意味があるッてんだよ、ああ~ん? と憎まれ口を心の中で叩いたものですが、まさか使い道が全くないと思っていた internal のお世話になるとは…… 隔世の感がいたしますね。
AqIterator
イテレートパターンのメインとなる AqIterator クラスには public な要素が多くなります。
まずはメソッドから。
- hasNext()
- 取り出せるオブジェクトの有無を判定
- next()
- 現在のオブジェクトを取り出し、ポジションを進める
- reset(mode:String="normal")
- イテレータのリセット
上記のふたつは、各種デザインパターン解説のイテレータの項に必ず記載されていることなので説明を省き、reset メソッドについてのみ記述します。
コレクションの配列へのアクセス制御が、今回作っているイテレータの独自性です。
で、そのアクセスのモードを切り替えるタイミングをどこに持ってこようかといろいろ考えたところ、リセットしたときにモードも指定する、というアルゴリズムにするのが一番分かり易いし、汎用性も高いだろうという結論に達しました。
なお、このようなオレ仕様を採用しなければ、reset は当然、引数なしのメソッドになります。 しかし上述のとおり、マイカスタムでは引数が必要。 このような齟齬があるので AqIterator のインターフェイスである IIterator には reset メソッドを定義しなかったのです。
reset メソッドの引数は、アクセス配列のかき混ぜ方を指定します。 規定値は正順。
で、その reset メソッドの引数となる文字列ですが、そのままでは間違えたりする可能性も高いので、AqIterator クラスの static const なプロパティとして設定することにしました。
- NORMAL:String = "normal"
- 正順
- REVERSE:String = "reverse"
- 逆順
- RANDOM:String = "random"
- 乱順
実際にこれらのクラスを協業させてイテレータパターンを実行するときの流れとしては、以下のようになります。
- AqCollection でオブジェクトを格納格納格納ひたすら格納
- 格納が完了したら AqCollection.iterator で AqIterator 生成
- 以後 AqCollection は完全シカト、AqIterator だけと蜜月モード
なお 2. のステップは直接、new AqIterator(AqCollection); でも可。
次回は本稿の最終回。 イテレータを使ったデモンストレーションです。
シリーズ