##概要
コンテナオブジェクトと、その要素へのアクセス、走査のためのインターフェイスを独立に実装したパターン
以下の4種類のクラスからなる
- Iteratorクラス(コンテナオブジェクトの要素にアクセス、走査するためのインターフェイスを定義)
- ConcreteIteratorクラス(1.で定義したインターフェイスを実装する)
- Aggregateクラス(1.を生成するためのインターフェイスを定義)
- ConcreteAggregateクラス(3.で定義したインターフェイスに対して適切な2.のインターフェイスを生成して返す)
##具体例と実装
エンタメサイトの一覧ソート機能を例にすると
上記1~4はそれぞれ
- 作品イテレータークラス
- 新着順クラス
- 作品一覧クラス
- 映画一覧クラス
が対応する。
コードの詳細は以下
iterator.rb
class Iterator
def initialize(aggregate)
@aggregate = aggregate
@index = 0
end
def has_next?
end
def next_item
end
end
recent_iterator.rb
class RecentIterator < Iterator
def initialize(aggregate)
@aggregate = aggregate.sort do |(_k1, v1), (_k2, v2)|
v1[:published_at] <=> v2[:published_at]
end
@index = 0
end
def has_next?
@index < @aggregate.size
end
def next_item
@index = @index + 1
item = self.has_next? ? @aggregate.get_by_index(@index) : nil
end
end
aggregate.rb
class Aggregate
def initialize
@works = []
end
def get_by_index(index)
end
def size
end
end
MovieAggregate.rb
class MovieAggregate < Aggregate
def initialize
@works = []
end
def add_work(work)
@works << work
end
def get_by_index(index)
@works[index]
end
def size
@works.size
end
end
client.rb
movie_list = MovieAggregate.new
# 映画作品を追加していく
movie_list.add_work(...)
...
iterator = RecentIterator(movie_list)
while iterator.has_next?
work = iterator.next_item
puts work.title
end
##メリット
- コンテナオブジェクトと走査のインターフェイスが独立しているため、コンテナの内部表現を公開せずに要素へのアクセスを提供出来る
- あるコンテナオブジェクトに対して複数の走査をサポートできる
- 異なるコンテナに対して、同一のインターファイスで要素にアクセス出来る
##まとめ
コンテナの内部表現を隠蔽して要素へのアクセスを提供するパターン
あるコンテナの要素への複数のアクセス方法が必要な場合、または複数のコンテナの要素に対してアクセスする共通のインターファイスが必要な場合に用いる