#はじめに
詳しいことや他のパターンは**デザインパターンをJavaScriptとJavaでの実装を比較して理解する**に書いて行きます。
JavaScriptの例はJavaのを見て書きました。
クラス型・プロトタイプ型、型付の強弱、アクセス修飾子など特徴の違いなどは活かしていません。(必要のないgetterなどもあります)
ご了承ください。
#Iteratorパターン
何かがたくさん集まっているときに、それを順番に指し示していき、全体をスキャンしていく処理を行うためのもの
iterateという英単語は何かを繰り返すという意味です。日本語では反復子と呼ばれることがある
##Javaでの実装例
本棚に数冊の本があり、その本棚ごとの本の冊数を数えるプログラム
###コード
public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(4);
bookShelf.appendBook(new Book("Around the World in 80 Days"));
bookShelf.appendBook(new Book("Bible"));
bookShelf.appendBook(new Book("Chinderella"));
bookShelf.appendBook(new Book("Dabby-Long-Legs"));
Iterator it = bookShelf.iterator();
while (it.hasNext()) {
Book book = (Book)it.next();
System.out.println(book.getName());
}
}
}
public interface Aggregate {
public abstract Iterator iterator();
}
public class BookShelf implements Aggregate {
private Book[] books;
private int last = 0;
public BookShelf(int maxsize) {
this.books = new Book[maxsize];
}
public Book getBookAt(int index) {
return books[index];
}
public void appendBook(Book book) {
this.books[last] = book;
last++;
}
public int getLength() {
return last;
}
public Iterator iterator() {
return new BookShelfIterator(this);
}
}
public class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public interface Iterator {
public abstract boolean hasNext();
public abstract Object next();
}
public class BookShelfIterator implements Iterator {
private BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
public boolean hasNext() {
if (index < bookShelf.getLength()) {
return true;
} else {
return false;
}
}
public Object next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
##JavaScriptの例
###コード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Iterator</title>
</head>
<body>
<script src="Main.js"></script>
<script src="Interface.js"></script>
<script src="Aggregate.js"></script>
<script src="BookShelf.js"></script>
<script src="Book.js"></script>
<script src="iterator.js"></script>
<script src="BookShelfIterator.js"></script>
</body>
</html>
MAIN = {};
MAIN.init = function() {
var bookShelf = new BookShelf();
bookShelf.appendBook(new Book("Around the World in 80 Days"));
bookShelf.appendBook(new Book("Bible"));
bookShelf.appendBook(new Book("Chinderella"));
bookShelf.appendBook(new Book("Dabby-Long=legs"));
var it = bookShelf.iterator();
while (it.hasNext()) {
var book = it.next();
console.log(book.name);
}
};
window.addEventListener("load", MAIN.init);
/**
* @namespace INTERFACE
*/
INTERFACE = {};
/**
* 同じプロパティを持っているか判定
* @static
* @method implements
*/
INTERFACE.implements = function(child, Pr) {
var parent = new Pr();
for (var p in parent) {
if (!(p in child)) {
console.error(child.constructor.name + "クラス(関数)に" + p + "メソッドが宣言されていません。");
}
}
};
var Aggregate = function() {};
Aggregate.prototype.iterator = function() {};
var BookShelf = function() {
this.books = [];
this.last = 0;
INTERFACE.implements(this, Aggregate);
};
BookShelf.prototype = {
constructor: BookShelf,
getBookAt: function(index) {
return this.books[index];
},
appendBook: function(book) {
this.books[this.last] = book;
this.last += 1;
},
getLength: function() {
return this.last;
},
iterator: function() {
return new BookShelfIterator(this);
}
};
var Book = function(name) {
this.name = name;
};
Book.prototype.getName = function() {
return this.name;
};
var Iterator = function() {};
Iterator.prototype = {
constructor: Iterator,
hasNext: function() {},
next: function() {}
};
var BookShelfIterator = function(bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
INTERFACE.implements(this, Iterator);
};
BookShelfIterator.prototype = {
constructor: BookShelfIterator,
hasNext: function() {
if (this.index < this.bookShelf.getLength()) {
return true;
} else {
return false;
}
},
next: function() {
var book = this.bookShelf.getBookAt(this.index);
this.index += 1;
return book;
}
}
##ある本に書いてあったJavaScriptでのIteratorパターン
Iteratorパターンは振る舞いなので、hasNext()とnext()があればいいってことなんですかね?
自分は再利用性が出来ない感じがするのでちょっと。。。って感じです
参考までに
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Iterator</title>
</head>
<body>
<script src="Main.js"></script>
</body>
</html>
MAIN = {};
MAIN.init = function() {
while(egg.hasNext()) {
console.log(egg.next());
}
};
var egg = (function() {
var index = 0,
data = [1, 2, 3, 4, 5],
length = data.length;
return {
next: function() {
var element;
if (!this.hasNext()) {
return null;
}
element = data[index];
index = index + 1;
return element;
},
hasNext: function() {
return index < length;
}
};
}());
window.addEventListener("load", MAIN.init);
##Iteratorパターンの登場人物
###Iterator(反覆子)の役
要素を順番にスキャンしていくインタフェースを定める役
サンプルプログラム⇒Iterator(interface)
###ConcreateIterator(具体的な反復子)の役
Iterator役が定めたインタフェースを実際に実装する役
サンプルプログラム⇒BookShelfIterator(class)
###Aggregate(集合体)の役
Iterator役を作り出すインターフェースを定める役
サンプルプログラム⇒Aggregate(interface)
###ConcreateAggregate(具体的な集合体)の役
Aggregate役が定めたインタフェースを実際に実装する役
サンプルプログラム⇒BookShelf(class)
##Iteratorパターンの必要性
Iteratorパターンを使わなくても、for文などで回せばいいと思える
Iteratorを使う大きな理由は、Iteratorを使うことで、実装とは切り離して、数え上げを行うことが出来るからである
##イテレータの種類
今回の例では順方向に一度だけスキャンする単純なものだが、他にもある
- 最後尾から開始して逆方向に進む
- 順方向にも逆方向にも行く(next, previousメソッドの両方を持つ)
- 番号を指定して、そこから始める
- etc...
#関連しているパターン
- Visitorパターン
- Compositeパターン
- Factory Methodパターン
#参考
増補改訂版Java言語で学ぶデザインパターン入門
JavaScriptパターン――優れたアプリケーションのための作法