search
LoginSignup
1

More than 5 years have passed since last update.

posted at

updated at

IteratorパターンをJavaとJavaScriptのコードを比較して理解する

はじめに

詳しいことや他のパターンはデザインパターンをJavaScriptとJavaでの実装を比較して理解するに書いて行きます。
JavaScriptの例はJavaのを見て書きました。
クラス型・プロトタイプ型、型付の強弱、アクセス修飾子など特徴の違いなどは活かしていません。(必要のないgetterなどもあります)
ご了承ください。

Iteratorパターン

何かがたくさん集まっているときに、それを順番に指し示していき、全体をスキャンしていく処理を行うためのもの
iterateという英単語は何かを繰り返すという意味です。日本語では反復子と呼ばれることがある

Javaでの実装例

本棚に数冊の本があり、その本棚ごとの本の冊数を数えるプログラム

クラス図

Iterator.png

コード

Main.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());
        }        
    }
}
Aggregate.java
public interface Aggregate {
    public abstract Iterator iterator();
}
BookShelf.java
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);
    }
}
Book.java
public class Book {
    private String name;

    public Book(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
Iterator.java
public interface Iterator {
    public abstract boolean hasNext();
    public abstract Object next();    
}
BookShelfIterator.java
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の例

コード

index.html
<!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.js
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);
Interface.js
/**
 * @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 + "メソッドが宣言されていません。");
        }
    }
};
Aggregate.js
var Aggregate = function() {};
Aggregate.prototype.iterator = function() {};
BookShelf.js
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);
    }
};
Book.js
var Book = function(name) {
    this.name = name;
};

Book.prototype.getName = function() {
    return this.name;
};
Iterator.js
var Iterator = function() {};
Iterator.prototype = {
    constructor: Iterator,

    hasNext: function() {},
    next: function() {}
};
BookShelfIterator.js
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()があればいいってことなんですかね?
自分は再利用性が出来ない感じがするのでちょっと。。。って感じです
参考までに

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Iterator</title>
</head>
<body>
    <script src="Main.js"></script>
</body>
</html>
Main.js
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パターンのクラス図

クラス図2.png

Iteratorパターンの必要性

Iteratorパターンを使わなくても、for文などで回せばいいと思える
Iteratorを使う大きな理由は、Iteratorを使うことで、実装とは切り離して、数え上げを行うことが出来るからである

イテレータの種類

今回の例では順方向に一度だけスキャンする単純なものだが、他にもある

  • 最後尾から開始して逆方向に進む
  • 順方向にも逆方向にも行く(next, previousメソッドの両方を持つ)
  • 番号を指定して、そこから始める
  • etc...

関連しているパターン

参考

増補改訂版Java言語で学ぶデザインパターン入門
JavaScriptパターン――優れたアプリケーションのための作法

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1