イテレータパターンについて学習する。

イテレータとは、プログラミング言語において配列やそれに類似する集合的データ構造の各要素に対する繰り返し処理の抽象化である。

Wikipediaより

今回はJava SE 16にて実装しています。(今回の実装であればjava 1.5 以上であればOK ※ forEachを使うとなると関数型プログラミングが導入された1.8以上が必要になります)

イテレータパターンとは

イテレータを作成するためのパターン。Javaではイテレータパターンを実装するためのインターフェイスが存在します。このインターフェイスを使って実装することで可読性も上がると思われます。

クラス図と結果

まずは先に実際に私が書いたコードとクラス図を載せます。

基本的なIteratorパターン

上二つのインターフェイスがjavaによって用意されているインターフェイスです。

実行結果はこんな感じ

>java Main
Prius : Red
Prius : Green
Aqua : Blue

イメージとしては、駐車場に車を格納し、イテレータが駐車場に格納された車を手前から順番に見ていくという感じです。(分かりづらかったら、ごめんなさい)

以下にコードを載せます。

public class Car {

    private final String model;
    private final String color;

    public Car(String model,String color){
        this.model = model;
        this.color = color;
    }

    public String getModel(){
        return model;
    }

    public String getColor(){
        return color;
    }
}
import java.util.Iterator;

public class ParkingArea implements Iterable<Car>{
    
    private Car[] cars;
    private int max_size;
    private int last;

    public ParkingArea(int max_size){
        this.max_size = max_size;
        cars = new Car[max_size];        
        last = 0;
    }

    public int getLength(){
        return max_size;
    }
    
    public Car getCarAt(int index){
        return cars[index];
    }

    public void appendCar(Car car){
        cars[last] = car;
        last++;
    }

    @Override
    public Iterator<Car> iterator(){
        return new ParkingAreaIterator(this);
    }
}
import java.util.Iterator;
import java.util.NoSuchElementException;

public class ParkingAreaIterator implements Iterator<Car>{

    private int index;
    private ParkingArea parkingArea;

    public ParkingAreaIterator(ParkingArea parkingArea){
        this.parkingArea = parkingArea;
        index = 0;
    }  

    public boolean hasNext(){
        if(index < parkingArea.getLength() - 1){
            if(parkingArea.getCarAt(index) != null){
                return true;
            }
        }
        return false;
    }

    public Car next() {

        if(!hasNext()){
            throw new NoSuchElementException();
        }

        Car car = parkingArea.getCarAt(index);
        index++;
        return car;
    }
}
import java.util.Iterator;

public class Main {

    public static void main(String[] args){

        int max_size = 10;

        ParkingArea parkingArea = new ParkingArea(max_size);
        
        parkingArea.appendCar(new Car("Prius","Red"));
        parkingArea.appendCar(new Car("Prius","Green"));
        parkingArea.appendCar(new Car("Aqua","Blue"));
        Iterator<Car> parkingAreaIterator = parkingArea.iterator();
        
        while(parkingAreaIterator.hasNext()){
            Car car = parkingAreaIterator.next();
            System.out.println(car.getModel() + " : " + car.getColor());
        }
    }

}

必要なもの

イテレータパターンを利用するうえで必要なものは以下です。

  1. 格納したいオブジェクト (上記のコードではCarオブジェクト)
  2. 格納する入れ物 (上記のコードではParkingAreaオブジェクト)
  3. 入れ物にアクセスするイテレータ (上記のコードではParkingAreaIteratorオブジェクト)

イテレータパターンを利用する利点

このパターンを利用する利点は、それぞれの機能を独立させることが出来るという点です。

ここで以下のような疑問が出てくると思います。

なぜ それぞれの機能を独立させることが出来る ことが嬉しいのか

それぞれの機能を上手く独立させると、コードの変更が容易になります。

例えば以下のMain.javaの

while(parkingAreaIterator.hasNext()){
            Car car = parkingAreaIterator.next();
            System.out.println(car.getModel() + " : " + car.getColor());
        }

このwhile文の部分に注目すると、ParkingAreaクラスのメソッドやフィールドを使用していないことが分かります。

このようにParkingAreaという入れ物にアクセスする必要がなくなるので、ParkingAreaクラスに変更があったとしても利用者はそれを気にせずに扱う事ができます。

利用者が変更を意識させずに扱うことが出来る これが嬉しいのです。

欠点

  • 慣れてないと分かりづらい
  • コード量が少し多くなる

欠点としては以上のようなことが挙げられます。

しかし大規模な開発になればなるほど、このような冗長なコードが真価を発揮します。

終わり

今回はここまで、ありがとうございました。

コメント

タイトルとURLをコピーしました