Strategyパターンの実装例 (Java)
[履歴] [最終更新] (2013/08/13 04:57:55)

概要

一般にある問題を解くためのアルゴリズムは複数存在します。このアルゴリズム (Strategy) 部分をinterfaceで要請した形式に合わせて実装し、委譲を用いて分離することで状況に応じて切り替えて使用できるようにします。切り替え可能なアルゴリズム以外の部分は、委譲でアルゴリズムを利用する側に実装します。また、Mainから直接Strategyを利用することは避けましょう。

サンプルコード

ある範囲に存在する素数を以下の二つのアルゴリズムで列挙します:

  • それぞれの値を一つ一つ見ていき、それが素数かどうか判断する
  • エラトステネスの篩 (Sieve of Eratosthenes)

sample.java

class Sample {
    public static void main(String args[]) {
        int rangeTo = 100;
        PrimeGenerator eachGen = new PrimeGenerator(new EachStrategy(rangeTo));
        PrimeGenerator sieveGen = new PrimeGenerator(new SieveStrategy(rangeTo));

        while(eachGen.hasNext()) System.out.print(eachGen.next() + " ");
        System.out.println("");
        while(sieveGen.hasNext()) System.out.print(sieveGen.next() + " ");
        System.out.println("");
    }
}

PrimeGenerator.java

class PrimeGenerator {
    private Strategy strategy;
    public PrimeGenerator(Strategy strategy) {this.strategy = strategy;}
    public int next() {return strategy.next();}
    public boolean hasNext() {return strategy.hasNext();}
}

Strategy.java

interface Strategy {
    public abstract int next();
    public abstract boolean hasNext();
}

EachStrategy.java

class EachStrategy implements Strategy {
    private int max;
    private int nextPrime;
    public EachStrategy(int max) {
        this.max=max;
        nextPrime=2;
    }
    public int next() {return nextPrime++;}
    public boolean hasNext() {
        do {
            boolean isPrime=true;
            for(int i=2; i*i<=nextPrime; ++i) {
                if(nextPrime%i==0) {isPrime=false; break;}
            }
            if(isPrime) return true;
        } while(++nextPrime <= max);
        return false;
    }
}

SieveStrategy.java

class SieveStrategy implements Strategy {
    private boolean isPrime[];
    private int nextPrime;
    public SieveStrategy(int max) {
        this.isPrime = new boolean[max+1];
        isPrime[0]=isPrime[1]=false;
        for(int i=2; i<isPrime.length; ++i) isPrime[i]=true;
        nextPrime=2;
    }
    public int next() {return nextPrime++;}
    public boolean hasNext() {
        while(nextPrime<isPrime.length && !isPrime[nextPrime]) ++nextPrime;
        for(int i=nextPrime*2; i<isPrime.length; i+=nextPrime) isPrime[i]=false;
        return (nextPrime<isPrime.length) ? true : false;
    }
}

実行例

$ javac EachStrategy.java  PrimeGenerator.java  SieveStrategy.java  Strategy.java  sample.java && java Sample
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 
関連ページ