Iteratorパターンは、コレクションオブジェクトに含まれる要素を一つずつ順番に取り出すためのデザインパターンです。
オブジェクト指向プログラミングにおいて、コレクションの内部構造に依存せずにその要素を操作できるため、コードの柔軟性が向上します。
本記事では、GoFのIteratorパターンの基本概念から、その使い方、さらにJava、C++、C#での実装例を詳しく解説します。
Iteratorパターンとは
Iteratorパターンは、コレクション内の要素を順番にアクセスするためのインターフェースを提供します。
コレクションの内部実装を隠蔽し、外部から一貫した方法で要素にアクセスできるようにするため、コードの可読性とメンテナンス性が向上します。
Iteratorパターンの目的
Iteratorパターンの主な目的は、コレクションの内容を簡単かつ一貫した方法で走査できるようにすることです。
これにより、コレクションの内部構造が変更されても、イテレータを介してアクセスするコードは変更する必要がなくなります。
Iteratorパターンの構成要素
Iteratorパターンは主に以下の3つの構成要素で成り立っています。
Iteratorパターンの使い方
Iteratorパターンは、特にコレクションの種類が異なる場合でも一貫した方法でデータにアクセスしたい場合に有効です。
以下の使い方のセクションで、Iteratorパターンの具体的な利用方法を説明します。
コレクションの種類とIterator
様々なコレクション(例えば、リスト、セット、マップ)でIteratorパターンを使うことができます。
これにより、コレクションごとの操作の違いを意識せずに、一貫した方法でデータを扱うことが可能です。
Iteratorパターンのメリット
Iteratorパターンを使用することで、以下のメリットがあります。
Iteratorパターン実装サンプル
ここでは、Iteratorパターンの実装例をJava、C++、C#それぞれで紹介します。
JavaでのIteratorパターン実装
Javaの標準ライブラリにはIteratorインターフェースが組み込まれており、以下のコードでIteratorパターンを実装することができます。
// JavaでのIteratorパターン実装
import java.util.Iterator;
import java.util.ArrayList;
class ConcreteIterator implements Iterator<String> {
private ArrayList<String> collection;
private int position = 0;
public ConcreteIterator(ArrayList<String> collection) {
this.collection = collection;
}
@Override
public boolean hasNext() {
return position < collection.size();
}
@Override
public String next() {
if (this.hasNext()) {
return collection.get(position++);
}
return null;
}
}
class Client {
public static void main(String[] args) {
ArrayList<String> items = new ArrayList<String>();
items.add("Item 1");
items.add("Item 2");
items.add("Item 3");
ConcreteIterator iterator = new ConcreteIterator(items);
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
C++でのIteratorパターン実装
以下はC++でのIteratorパターンの実装例です。
// C++でのIteratorパターン実装
#include <iostream>
#include <vector>
using namespace std;
class Iterator {
public:
virtual bool hasNext() = 0;
virtual string next() = 0;
};
class ConcreteIterator : public Iterator {
private:
vector<string> collection;
int position = 0;
public:
ConcreteIterator(vector<string> collection) : collection(collection) {}
bool hasNext() override {
return position < collection.size();
}
string next() override {
if (hasNext()) {
return collection[position++];
}
return "";
}
};
int main() {
vector<string> items = {"Item 1", "Item 2", "Item 3"};
ConcreteIterator iterator(items);
while (iterator.hasNext()) {
cout << iterator.next() << endl;
}
return 0;
}
C#でのIteratorパターン実装
C#でのIteratorパターン実装例です。
// C#でのIteratorパターン実装
using System;
using System.Collections.Generic;
class ConcreteIterator : IEnumerator<string> {
private List<string> collection;
private int position = -1;
public ConcreteIterator(List<string> collection) {
this.collection = collection;
}
public bool MoveNext() {
position++;
return (position < collection.Count);
}
public void Reset() {
position = -1;
}
public string Current {
get {
try {
return collection[position];
} catch (IndexOutOfRangeException) {
throw new InvalidOperationException();
}
}
}
object System.Collections.IEnumerator.Current {
get {
return Current;
}
}
public void Dispose() { }
}
class Program {
static void Main(string[] args) {
List<string> items = new List<string>() { "Item 1", "Item 2", "Item 3" };
ConcreteIterator iterator = new ConcreteIterator(items);
while (iterator.MoveNext()) {
Console.WriteLine(iterator.Current);
}
}
}
まとめ
Iteratorパターンは、コレクションの内部構造に依存せず、要素を順番にアクセスするための有用なデザインパターンです。
特に、コレクションの種類が異なる場合でも一貫した方法で操作できるという点が大きなメリットです。
この記事では、Java、C++、C#での実装例を紹介しましたが、どの言語でも同様の概念で実装可能です。これにより、複雑なコレクションを扱う際のコードの柔軟性が向上し、メンテナンス性も向上します。