12 Dec 2014, 15:59

ConcurrentModificationException が Java で発生したときの対処方法

はじめに

ConcurrentModificationException が Java で発生したときの対処方法.

以下のようなコードを実行すると, 例外発生.

import java.util.Set;
import java.util.HashSet;

public class ConcurrentModification {
    public static void main (String[] args) {
        Set<Integer> set = new HashSet<Integer>();
        for (int i = 0; i < 5; i++)
            set.add (i);

        for (Integer i: set) {
            if (i == 3) {
                set.remove (i);
            }
        }
    }
}
Exception in thread "main" java.util.ConcurrentModificationException
   at java.util.HashMap$HashIterator.nextEntry (HashMap.java:922)
   at java.util.HashMap$KeyIterator.next (HashMap.java:956)
   at ConcurrentModification.main (ConcurrentModification.java:10)

原因は, iterater で for 文を回している時に, 要素を削除しようとしたから.

回避方法

その 1: イテレータを利用しない

イテレータなんてつかってかっこつけているのが悪い. Index で for 文をまわす

for (int i=0; i < set.size (); i++) {
    if (i == 3) {
        set.remove (i);
    }
}

その 2 Concurrent ライブラリを利用する

ConcurrentHashMap を利用する. ただし, ConcurrentHashSet はない…以下のように対応

Set<Integer> set = Collections.newSetFromMap (new ConcurrentHashMap<Integer, Boolean>());

その 3 コレクションをコピーして回す

すこし冗長か?

Set<Integer> set = new HashSet<Integer>();
for (int i = 0; i < 5; i++)
    set.add (i);

Set<Integer> set2 = new HashSet<Integer>();
set2.addAll (set);

for (Integer i: set2) {
    if (i == 3) {
        set.remove (i);
    }
}

おわりに

やりかたはいろいろある. 1 がいいかな…

BookMark

11 Dec 2014, 15:30

JUnit のテストケースをステートフルで利用する

はじめに

JUnit で, 結合テスト (Integration test), シナリオテストを書きたい.

トランザクションごとに長いテストを書く必要がある.

複数のトランザクションを順に処理していったときに, オブジェクトの状態の変化を検証したい.

JUnit はテストケースが独立

はじめ, トランザクションごとにテストケースを書いていたが, うまく動かない.. オブジェクトの状態が初期化されてしまう.

これは, JUnit の設計思想だった.

つまり, 各テストケースは独立だということ. テストで使用するオブジェクトはテストケース内で生成されて, テストケース内で消滅する.

たとえば

たとえば, このテストは失敗する. number は 0 が入っている.

import static org.junit.Assert.*;

import org.junit.Test;

public class MemoryTest {

    static int number;

    @Test
    public void test () {
        number = 1;
    }

    @Test
    public void test2 () {
        assertEquals (1, number);
    }
}

static を利用する

テスト間で状態を引き継ぐためには, 変数に static 修飾子をつける.

こうすると, 各テストケースの独立を破ることができる.

package test;

import static org.junit.Assert.*;

import org.junit.Test;

public class MemoryTest {

    static int number;
    static Foo foo;
    static Foo bar; 
    static Foo pee;     

    @Test
    public void test () {
        number = 1;
        foo = new Foo (1);
        bar = new Foo (foo);
        pee = new Foo ();       
    }

    @Test
    public void test2 () {
        assertEquals (1, number);
        assertEquals (1, foo.i);
        assertEquals (1, bar.foo.i);        
        assertEquals (2, pee.foo.i);
        foo.plus (3);
    }

    @Test
    public void test3 () {
        assertEquals (4, foo.i);
    }

}

class Foo {
    public int i;
    public Foo foo;

    public Foo (int i) {
        this.i = i;
    }

    public Foo () {
        this.foo = new Foo (2);
    }

    public Foo (Foo foo) {
        this.foo = foo;
    }

    public void plus (int i){
        this.i += i;
    }
}

テストの実行順序を制御する

JUnit のテストが実行される順番はランダム.

これだと, ステートフルなテストには不向きだ.

テストの実行順序を指定するには, 以下の方法がある

  • @FixMethodOrder (MethodSorters.NAME_ASCENDING) をクラスの頭に設定
  • メソッド名を 実行したいものから abc 順に変更.
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.junit.FixMethodOrder;

@FixMethodOrder (MethodSorters.NAME_ASCENDING)
public class MemoryTest {

    static int number;
    static Foo foo;
    static Foo bar; 
    static Foo pee;     

    @Test
    public void test () {
        number = 1;
        foo = new Foo (1);
        bar = new Foo (foo);
        pee = new Foo ();       
    }

    @Test
    public void test2 () {
        assertEquals (1, number);
        assertEquals (1, foo.i);
        assertEquals (1, bar.foo.i);        
        assertEquals (2, pee.foo.i);
        foo.plus (3);
    }

    @Test
    public void test3 () {
        assertEquals (4, foo.i);
    }

}

10 Dec 2014, 15:56

Factory Method と Abstract Factory の違いを順に理解する

はじめに

デザインパターンにでてくる Factory Method と Abstract Factory.

なんだか, いつになっても違いが分からない… というわけで一旦整理してみることにした.

能書き

まずは, 一般的な説明をネットからひろう.

Factory の原則

生成と実装を分離することで, プログラムはシンプルになる.

  • 生成パラメータの指定方法をシンプルに
  • 生成後の管理をシンプルに
  • 生成するオブジェクトの指定方法をシンプルに

特定のケースで特定のオブジェクトを生成するのは手続き思考的.

2 つをわけて考えることで設計に集中.

  • 動作方法
  • 生成,管理方法

Factory Method

オブジェクトの生成を行う時のインタフェースを規定して, インスタンス化するクラスを決定するのはサブクラスに任せる.

factoryMethod の中でオブジェクトの生成をすることで, 生成を生成オブジェクト (メソッド) 内にカプセル化.

Abstract Factory

関連するオブジェクト群を, その具象クラスを明確にせずに生成するための インタフェースを提供する.

関連するインスタンス群を生成するための API を集約することによって, 複数のモジュール群の再利用を効率化することを目的とする.

実装は意識せずに, インタフェース (API) のみで, 抽象的な部品をつくりあげる.

Factory Method 自体のカプセル化. マルチ Factory Method. Factory Methods.

両者の違い

Factory Method

ファクトリのクライアントとなるオブジェクトが, ファクトリオブジェクトにインスタンスの生成を委譲する.

  • 親クラスである Creator クラスが子クラスである

ConcreteCreator クラスにオブジェクトの生成を委ねる

  • Creator クラスと ConcreteCreator クラスとの関連である.
  • [オブジェクト生成] の抽象化にポイントを置いたパターン

Abstract Factory

親クラスであるファクトリが, 実際のオブジェクトの生成をサブクラスに委譲する

  • Client のインスタンスが ConcreteFactory のインスタンスにオブジェクトの生成を委ねる
  • オブジェクト同士の関連
  • [関連するオブジェクト群をまとめて生成するための手順] の抽象化

コードから理解する

能書きはいくら読んでもわからない.

というわけで, コードから理解する.

Factory Method

パターン未適用

まずは基本から. if-else が汚いことがよくわかる.

public class FactoryMethodSample {
    enum Type { FIRST, SECOND }

    public static void main (String[] args) {
        Type type;
      Alphabet alphabet;

        type = Type.FIRST;
        if (type == Type.FIRST) {
            alphabet = new A ();
        }
        else {
            alphabet = new B ();
        }
        alphabet.whoAreYou ();

        type = Type.SECOND;
        if (type == Type.FIRST) {
            alphabet = new A ();
        }
        else {
            alphabet = new B ();
        }
        alphabet.whoAreYou ();
    }
}

abstract class  Alphabet {
    abstract void whoAreYou ();
}

class A extends  Alphabet {
    void whoAreYou () { System.out.println ("I'm A");}
}

class B extends  Alphabet {
    void whoAreYou () { System.out.println ("I'm B");}
}

static ファクトリーメソッド適用

Factory の原則にしたがうと, 生成部分と振る舞いをわけることがシンプルなコードへの第一歩.

ということで, 生成部分をサブメソッドに抽出する.

これを, Effective Java では, static ファクトリーメソッドといっている.

public class StaticFactoryMethodSample {
    enum Type { FIRST,SECOND }

    public static void main (String[] args) {
        Type type;
        Alphabet alphabet;

        type = Type.FIRST;
        alphabet = factoryMethod (type);
        alphabet.whoAreYou ();

        type = Type.SECOND;
        alphabet = factoryMethod (type);
        alphabet.whoAreYou ();
    }

    static Alphabet factoryMethod (Type type) {
        if (type == Type.FIRST) {
            return new A ();
        }
        else {
            return new B ();
        }
    }
}

abstract class Alphabet {
    abstract void whoAreYou ();
}

class A extends Alphabet {
    void whoAreYou () { System.out.println ("I'm A");}
}

class B extends Alphabet {
    void whoAreYou () { System.out.println ("I'm B");}
}

ファクトリーメソッド パターン適用

そして, これがファクトリーメソッド パターン適用版. static ファクトリメソッドをオブジェクトに抽出.

抽象クラスに生成メソッドを定義して, サブクラスで実装する.

if-else 文が消滅しているところに注目.

public class FactoryMethodSample {
    public static void main (String[] args) {
        Creator creator;
        Alphabet alphabet;

        creator = new CreatorA ();
        alphabet = creator.factoryMethod ();
        alphabet.whoAreYou ();

        creator = new CreatorB ();
        alphabet = creator.factoryMethod ();
        alphabet.whoAreYou ();
    }
}

abstract class Creator {
    abstract Alphabet factoryMethod ();
}

class CreatorA extends Creator {
    Alphabet factoryMethod () {
        return new A ();
    }
}

class CreatorB extends Creator {
    Alphabet factoryMethod () {
        return new B ();
    }
}

abstract class Alphabet {
    abstract void whoAreYou ();
}

class A extends Alphabet {
    void whoAreYou () { System.out.println ("I'm A");}
}

class B extends Alphabet {
    void whoAreYou () { System.out.println ("I'm B");}
}

Abstract Factory

つぎに, Abstract Factory は Factory Method のカプセル化に過ぎないことを示す.

Factory Method を発展させたのが, Abstract Factory.

ファクトリメソッドのソースに Number という概念を加える. Alphabet と Number には関係がある.

Abstract Factory は 関連ある複数のオブジェクトの生成のための API をひとつのオブジェクトに集約する.

パターン未適用

まずは, 汚いコードから.

public class AbstractFactorySample {
    enum Type { FIRST,SECOND }

    public static void main (String[] args) {
        Type type;
        Alphabet alphabet;
        Number number;

        type = Type.FIRST;
        if (type == Type.FIRST) {
            alphabet = new A ();
        }
        else {
            alphabet = new B ();
        }

        if (type == Type.FIRST) {
            number = new One ();
        }
        else {
            number = new Twe ();
        }
        alphabet.whoAreYou ();
        number.whoAreYou ();

        type = Type.SECOND;
        if (type == Type.FIRST) {
            alphabet = new A ();
        }
        else {
            alphabet = new B ();
        }

        if (type == Type.FIRST) {
            number = new One ();
        }
        else {
            number = new Twe ();
        }
        alphabet.whoAreYou ();
        number.whoAreYou ();
    }
}

abstract class Alphabet {
    abstract void whoAreYou ();
}

class A extends Alphabet {
    void whoAreYou () { System.out.println ("I'm A");}
}

class B extends Alphabet {
    void whoAreYou () { System.out.println ("I'm B");}
}

abstract class Number {
    abstract void whoAreYou ();
}

class One extends Number {
    void whoAreYou () { System.out.println ("I'm 1");}
}

class Twe extends Number {
    void whoAreYou () { System.out.println ("I'm 2");}
}

ファクトリメソッドパターン適用

ここで, まずはファクトリメソッドを適用して整理する.

public class AbstractFactorySample2 {

    public static void main (String[] args) {
        AlphabetCreator alphabetCreator;
        NumberCreator numberCreator;        
        Alphabet alphabet;
        Number number;

        alphabetCreator = new CreatorA ();
        numberCreator = new CreatorOne ();
        alphabet = alphabetCreator.factoryMethod ();
        number = numberCreator.factoryMethod ();
        alphabet.whoAreYou ();
        number.whoAreYou ();

        alphabetCreator = new CreatorB ();
        numberCreator = new CreatorTwe ();
        alphabet = alphabetCreator.factoryMethod ();
        number = numberCreator.factoryMethod ();
        alphabet.whoAreYou ();
        number.whoAreYou ();
    }
}

abstract class AlphabetCreator {
    abstract Alphabet factoryMethod ();
}

class CreatorA extends AlphabetCreator {
    Alphabet factoryMethod () {
        return new A ();
    }
}

class CreatorB extends AlphabetCreator {
    Alphabet factoryMethod () {
        return new B ();
    }
}

abstract class NumberCreator {
    abstract Number factoryMethod ();
}

class CreatorOne extends NumberCreator {
    Number factoryMethod () {
        return new One ();
    }
}

class CreatorTwe extends NumberCreator {
    Number factoryMethod () {
        return new Twe ();
    }
}

abstract class Alphabet {
    abstract void whoAreYou ();
}

class A extends Alphabet {
    void whoAreYou () { System.out.println ("I'm A");}
}

class B extends Alphabet {
    void whoAreYou () { System.out.println ("I'm B");}
}

abstract class Number {
    abstract void whoAreYou ();
}

class One extends Number {
    void whoAreYou () { System.out.println ("I'm 1");}
}

class Twe extends Number {
    void whoAreYou () { System.out.println ("I'm 2");}
}

Type と if-else 文が取り除かれてすっきり. しかし, まだ冗長なところがある.

そこで, alphabetCreator と NumberCreator をひとつにまとめる.

Abstract Factory パターン適用

public class AbstractFactorySample3 {

    public static void main (String[] args) {
        Creator creator;
        Alphabet alphabet;
        Number number;

        creator = new FirstCreator ();
        alphabet = creator.alphabetFactoryMethod ();
        number = creator.numberFactoryMethod ();
        alphabet.whoAreYou ();
        number.whoAreYou ();

        creator = new SecondCreator ();
        alphabet = creator.alphabetFactoryMethod ();
        number = creator.numberFactoryMethod ();
        alphabet.whoAreYou ();
        number.whoAreYou ();
    }
}

abstract class Creator {
    abstract Alphabet alphabetFactoryMethod ();
    abstract Number numberFactoryMethod (); 
}

class FirstCreator extends Creator {
    Alphabet alphabetFactoryMethod () {
        return new A ();
    }
    Number numberFactoryMethod () {
        return new One ();
    }
}

class SecondCreator extends Creator {
    Alphabet alphabetFactoryMethod () {
        return new B ();
    }
    Number numberFactoryMethod () {
        return new Twe ();
    }
}

abstract class Alphabet {
    abstract void whoAreYou ();
}

class A extends Alphabet {
    void whoAreYou () { System.out.println ("I'm A");}
}

class B extends Alphabet {
    void whoAreYou () { System.out.println ("I'm B");}
}

abstract class Number {
    abstract void whoAreYou ();
}

class One extends Number {
    void whoAreYou () { System.out.println ("I'm 1");}
}

class Twe extends Number {
    void whoAreYou () { System.out.println ("I'm 2");}
}

おわりに

本をよんでも分かりにくいことは, より単純な例に落とし込めば自分でも理解できる.

Abstract Factroy と Factory メソッドの関係が分かって, スッキリ.

09 Dec 2014, 15:52

Java に Pair はないの?

はじめに

2 つの Key をもつ Map を利用したい.

たしか, C++ には Pair があった. Java にはないの?

結論

ない.

じゃあどうするか?

自分で作成するしかない!

class Pair<F, S> {
    public final F first;
    public final S second;

    Pair (F first, S second) {
        this.first = first;
        this.second = second;
    }
}

しかし, これでは 2 つの Key をもつ Map としてうまく動作しない.

import java.util.Map;
import java.util.HashMap;

public class PairSample {
    public static void main (String[] args) {
        Map<Pair<Integer,Integer>, String> map = new HashMap<Pair<Integer,Integer>, String>();

        Pair pair = new Pair (1,2);
        Pair pair2 = new Pair (1,2);        
        map.put (pair, "a");

        if (map.containsKey (pair2)) {
            System.out.println ("equal");
        }
        else {
            System.out.println ("not equal");           
        }
    }
}

秘密は, equals と hashCode にあった.

同一性と同値性

2 つのオブジェクトが同じ時, それらは同一性をもつという. hashCode () メソッドで検証する.

2 つのオブジェクトが保持する属性が同じとき, それらは同値性をもつという. equals () メソッドで検証する.

equals, hashCode はともに Object 型のメソッド.

以下のページが図つきでわかりやすい.

Map で二つのオブジェクトが同値だと判断するときは, equals メソッドをも ちいている.なので, このメソッドをオーバーロードして独自定義する必要がある.

実装例

今回やりたいことは, 同値性の確認なので, hashCode はなくてもいい.

ドキュメントによると, Hashcode があったほうが, HashMap の性能が上がるらしい.

@Override
public boolean equals (Object obj) {
    if (! (obj instanceof Pair))
        return false;
    Pair pair = (Pair) obj;
    return (first.equals (pair.first) && second.equals (pair.second));
}

@Override
public int hashCode () {
    return first.hashCode () ^ second.hashCode ();
}

Special Thanks

08 Dec 2014, 15:49

状態ありはプロトタイプパターンで, 状態なしはファクトリメソッドで実装 (Java)

はじめに

だんだん, タイトルが毎回同じになってきた.

今回はプロトタイプパターンの実装を Java で実施してみた.

Prototype パターン

生成するオブジェクトの原型をコピーして新しいオブジェクトを生成する.

Abstract Factory と似ている.

  • new でオブジェクトを生成すれば Abstract Factory./ Factory Method.
  • clone をつかう場合の Prototype.

複製を作成するためのメソッドを用意する. といういたって単純なもの.

プロトタイプ が複製を担当し, それ以外の生成における操作をクライアントが 担っている.

Map にテンプレートを登録しておいて, 利用するときに複製する. バイナリデータをマップにいれておいて, キーとなる名前をつけて管理する,など.

(実際に仕事では, バイナリのパケットをテンプレートから生成する処理につかった)

メリット

インスタンスのコンストラクタ引数で差分を渡すことで, クラスの数をかなり減らすことができる.

Java には, Clonable インタフェースがある.

利用シーン

  • Abstract Factory パターンでなされるように,

クライアント・アプリケーションにおいて オブジェクトの生成者をサブクラスにすることを回避する

  • 標準的な方法 (例えば’new’) で新しいオブジェクトを作ることによる

固有のコストが所与のアプリケーションにとって高すぎる時にそれを回避する.

サンプルコード

import java.util.HashMap;
import java.util.Map;

public class PrototypeSample {
    public static void main (String args[]) {
        printerFacotry factory = new printerFacotry ();
        Printer printer;

        printer = factory.create ("type a");
        printer.printMessage ();
        printer = factory.create ("type b");
        printer.printMessage ();
        printer = factory.create ("type c");
        printer.printMessage ();
    }
}

class Printer implements Cloneable {
    String str;

    public Printer (String str) {
        this.str = str;
    }

    public void printMessage () {
        System.out.println (str);
    }

    @Override
    public Printer clone () {
        Printer cloned = null;
        try {
            cloned = (Printer) super.clone ();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace ();
        }
        return cloned;
    }
}

class printerFacotry {
    Map<String, Printer> protoMap; 

    public printerFacotry (){
        protoMap = new HashMap<String, Printer>();
        protoMap.put ("type a", new Printer ("a"));
        protoMap.put ("type b", new Printer ("b"));
        protoMap.put ("type c", new Printer ("c"));
    }

    public Printer create (String type) {
        return protoMap.get (type).clone ();
    }
}

状態をもたないならば, プロトタイプは不要

無名クラスをクローンできるのかと思ったが, できなかった. そもそも, 無名クラスは状態を持たないので, クローンする必要がなかった.

この比較から以下のことが分かる.

  • 状態をもつオブジェクトをコピーするのはプロトタイプパターンが有用.
  • 状態をもたないオブジェクトは new で生成する ファクトリメソッドパターンが有用.

クロージャをわたす

Map のなかにクロージャを入れて, 好きな時に取り出すようにした.

これはけっこういいパターンかもしれない. 個人的に気に入った.

import java.util.HashMap;
import java.util.Map;

public class PrototypeSample {
    public static void main (String args[]) {
        printerFacotry factory = new printerFacotry ();
        Printer printer;

        printer = factory.create ("type a");
        printer.printMessage ();
        printer = factory.create ("type b");
        printer.printMessage ();
        printer = factory.create ("type c");
        printer.printMessage ();
    }
}

interface Printer {
    public void printMessage ();
}

class printerFacotry {
    Map<String, Printer> protoMap; 

    public printerFacotry (){
        protoMap = new HashMap<String, Printer>();
        protoMap.put ("type a", new Printer (){
            public void printMessage () { System.out.println ("a"); }
        });
        protoMap.put ("type b", new Printer (){
            public void printMessage () { System.out.println ("b"); }
        });
        protoMap.put ("type c", new Printer (){
            public void printMessage () { System.out.println ("c"); }
        });
    }

    public Printer create (String type) {
        return protoMap.get (type);
    }
}

クロージャ + 引数

さらに改良.

クロージャを Map に保存しておいて, 呼び出し時に外部から引数を与えるようにした.

これで, さらにメソッドが柔軟になった.

interface Printer {
    public void printMessage (String str);

}

class printerFacotry {
    Map<String, Printer> protoMap; 
    public printerFacotry (){
        protoMap = new HashMap<String, Printer>();
        protoMap.put ("type a", new Printer (){
            public void printMessage (String str) { System.out.println ("**"+str+"**"); }
        });
        protoMap.put ("type b", new Printer (){
            public void printMessage (String str) { System.out.println ("++"+str+"++"); }
        });
        protoMap.put ("type c", new Printer (){
            public void printMessage (String str) { System.out.println ("=="+str+"=="); }
        });
    }

    public Printer create (String type) {
        return protoMap.get (type);
    }
}

もはや, プロトタイプパターンの記事ではなくなっているが….

08 Dec 2014, 13:52

Java で Iterator Pattern を実装してみた

はじめに

最近, Gof のデザインパターンをすべて記事にしようと考えている.

そんなわけで, 今日は Iterator パターン. あまりに基本すぎて, 記事にするほどではないがするが…

Iterator パターンとは

オブジェクトの集合 (データ構造, コンテナ) があるとき, その集合の内部構造はカプセル化したままで, 要素に対して順にアクセスする方法を提供する.

コンテナオブジェクトの要素を列挙する手段を独立させることによって, コンテナの内部仕様に依存しない反復子を提供することを目的とする.

言語でサポートしていることがおおい. 拡張 for 文, for-each 文などと呼ばれる.

自前で実装するよりも, 言語に頼るほうがよい.

Java

Collection フレームワークでは, 反復子が利用できる.

List<Integer> list = LinkedList<Integer>
for (int i; list) {
System.out.println (i);
}

Iterator インタフェースを実装することで, 自前のクラスにイテレータを適用できる.

Iterator interface を実装する.

Iterator interface を実装した.

import java.util.Iterator;

public class IteratorSample {
    public static void main (String args[]) {
        myList list = new myList (1, new myList (2, new myList (3, null)));

        while (list.hasNext ()) {
            list.show ();
            list = list.next ();
        } 
        list.show ();
    }
}

class myList implements Iterator {
    myList next;
    int value;

    public myList (int value, myList next) {
        this.value = value;
        this.next = next;
    }

    @Override
    public boolean hasNext () {
        return (next != null);
    }

    @Override
    public myList next () {
        return next;
    }

    @Override
    public void remove () {
        // nop
    }

    public void show () {
        System.out.println (value);
    }
}

自前で hasNext, next メソッドを用意するよりも, Iterator interface を実装したほうが, 通に思われるというメリットがある.

関数型 Iterator パターン

関数型 Iterator パターンみたいなものを考えた. というよりも List の実装.

  • while を利用するのではなくて, 再帰を利用する.
import java.util.Iterator;

public class IteratorSample2 {
    public static void main (String args[]) {
        myList list = new myList (1, new myList (2, new myList (3, null)));
        whileLoop (list);
    }

    static void whileLoop (myList list) {
        list.show ();
        if (!list.hasNext ())
            return;
        else { 
            whileLoop (list.next ());
        }
    }
}

class myList implements Iterator<myList> {
    myList next;
    int value;

    public myList (int value, myList next) {
        this.value = value;
        this.next = next;
    }

    @Override
    public boolean hasNext () {
        return (next != null);
    }

    @Override
    public myList next () {
        return next;
    }

    @Override
    public void remove () {
        // nop
    }

    public void show () {
        System.out.println (value);
    }
}

なんか, 再帰のほうがいいな.おそまつさまでした.

07 Dec 2014, 15:33

Java で Chain of Responsibility Pattern を 末尾再帰で実装した

はじめに

Chain of Responsibility Pattern という, マイナーな Gof のパターンがある.

本をよんでみて, これって再帰関数を利用すればもっとシンプルにかけるん じゃないかとおもって, 試してみた.

Chain of Responsibility Pattern

責務を持たせたオブジェクトの Chain に 要求を渡していく.

要求は,

  • そのオブジェクトで処理できればそこで処理する
  • そのオブジェクトで処理できなければ, 次のオブジェクトに渡す.

パターン未適用

[sourcecode language=”java” title=””]
import java.util.List;
import java.util.LinkedList;

public class ChainOfResponsibilitySample {
public static void main (String[] args) {
List chain = new LinkedList();
chain.add (new A ());
chain.add (new B ());
chain.add (new C ());

for (Handler handler : chain) {
if (handler.isMatch (‘b’)) {
handler.execute ();
break;
}
}
}
}

abstract class Handler {
public abstract boolean isMatch (char c);
public abstract void execute ();
}

class A extends Handler {
public boolean isMatch (char c) { return c == ‘a’; }
public void execute () { System.out.println ("a hit"); }
}

class B extends Handler {
public boolean isMatch (char c) { return c == ‘b’; }
public void execute () { System.out.println ("b hit"); }
}

class C extends Handler {
public boolean isMatch (char c) { return c == ‘c’; }
public void execute () { System.out.println ("c hit"); }
}
[/sourcecode]

絶望ポイント

<div class="outline-text-3" id="text-unnumbered-4">
  <p>
    ここがきたない.
  </p>

  <p>
    制御側からいちいち判定用メソッドを読んだり, マッチしたらアクションを起動している.これが面倒.
  </p>

  <p>
    [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221;]<br /> for (Handler handler : chain) {<br /> if (handler.isMatch (&#8216;b&#8217;)) {<br /> handler.execute ();<br /> break;<br /> }<br /> }<br /> [/sourcecode]
  </p>

  <p>
    できれば, ひとつメソッドをよんだら, あとは好き勝手に処理されればいい.
  </p>

  <p>
    Amazon で本を注文するときは, ポチったら, あとはコンビニに勝手に届いて入ればいい.
  </p>
</div>

パターン適用

メリット

<div class="outline-text-3" id="text-unnumbered-6">
  <p>
    要求を出す側と, 要求を処理する側の結びつきが弱まる.
  </p>

  <p>
    具体的にいえば, ループを回さなくてすむ.
  </p>
</div>

コード

<div class="outline-text-3" id="text-unnumbered-7">
  [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221;]<br /> public class ChainOfResponsibilitySample {<br /> public static void main (String[] args) {<br /> Handler chain = new A (new B (new C (null)));<br /> chain.handle (&#8216;b&#8217;);<br /> }<br /> }</p> 

  <p>
    abstract class Handler {<br /> private Handler next;
  </p>

  <p>
    public Handler (Handler next) {<br /> this.next = next;<br /> }
  </p>

  <p>
    public void handle (char c) {<br /> if (isMatch (c))<br /> execute ();<br /> else<br /> next.handle (c);<br /> }
  </p>

  <p>
    abstract boolean isMatch (char c);<br /> abstract void execute ();<br /> }
  </p>

  <p>
    class A extends Handler {<br /> public A (Handler next){ super (next); }<br /> boolean isMatch (char c) { return c == &#8216;a&#8217;; }<br /> void execute () { System.out.println ("a hit"); }<br /> }
  </p>

  <p>
    class B extends Handler {<br /> public B (Handler next){ super (next); }<br /> boolean isMatch (char c) { return c == &#8216;b&#8217;; }<br /> void execute () { System.out.println ("b hit"); }<br /> }
  </p>

  <p>
    class C extends Handler {<br /> public C (Handler next){ super (next); }<br /> boolean isMatch (char c) { return c == &#8216;c&#8217;; }<br /> void execute () { System.out.println ("c hit"); }<br /> }<br /> [/sourcecode]
  </p>
</div>

感動のポイント

<div class="outline-text-3" id="text-unnumbered-8">
  <p>
    みよ! このシンプルさを.
  </p>

  <p>
    [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221;]<br /> public static void main (String[] args) {<br /> Handler chain = new A (new B (new C (null)));<br /> chain.handle (&#8216;b&#8217;);<br /> }<br /> [/sourcecode]
  </p>
</div>

こんなの, 関数型の考え方でかけば当たり前だ!

この主張をしたいがために, この記事を書いた.

関数型っぽくかけば, こんなの当たり前の方法.

[sourcecode language=”java” title=””]
public class ChainOfResponsibilityFinctional {
public static void main (String[] args) {

LinkedList chain = new LinkedList();
chain.add (new A ());
chain.add (new B ());
chain.add (new C ());

handle (chain, ‘b’);
}

static void handle (LinkedList chain, char c) {
Handler head = chain.element ();
chain.removeFirst ();
LinkedList tail = chain;
if (head == null)
return;
else {
if (head.isMatch (c)) {
head.execute ();
return;
}
else
handle (tail, c);
}
}
}

abstract class Handler {
public abstract boolean isMatch (char c);
public abstract void execute ();
}

class A extends Handler {
public boolean isMatch (char c) { return c == ‘a’; }
public void execute () { System.out.println ("a hit"); }
}

class B extends Handler {
public boolean isMatch (char c) { return c == ‘b’; }
public void execute () { System.out.println ("b hit"); }
}

class C extends Handler {
public boolean isMatch (char c) { return c == ‘c’; }
public void execute () { System.out.println ("c hit"); }
}
[/sourcecode]

感動のポイント

<div class="outline-text-3" id="text-unnumbered-10">
  <p>
    一行で一応処理できている.
  </p>

  <p>
    [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221;]<br /> handle (chain, &#8216;b&#8217;);<br /> [/sourcecode]
  </p>

  <p>
    末尾再帰を利用している. しかし, あんまりシンプルにかけないな&#x2026;
  </p>

  <p>
    [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221;]<br /> static void handle (LinkedList<Handler> chain, char c) {<br /> Handler head = chain.element ();<br /> chain.removeFirst ();<br /> LinkedList<Handler> tail = chain;<br /> if (head == null)<br /> return;<br /> else {<br /> if (head.isMatch (c)) {<br /> head.execute ();<br /> return;<br /> }<br /> else<br /> handle (tail, c);<br /> }<br /> }<br /> [/sourcecode]
  </p>

  <p>
    ただし, 呼び元で Handler に対してメッセージをおくっているところはかわらないか.
  </p>

  <p>
    Chain of responsibility は, chain のリスト構造のなかに, 責務をカプセル化している.
  </p>
</div>

おわりに

デコレータパターンやコンポジットパターンでも感じるが, Gof のデザインパターンは, 関数型で書いたほうが便利なことを がんばって OOP で書いているように思えるのだが.

関数型デザインパターン

<div class="outline-text-3" id="text-unnumbered-12">
  <p>
    ネットで調べたら, やはり同じことを考えている人はいるようだ.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://sujitpal.blogspot.jp/2013/06/functional-chain-of-responsibility.html">Salmon Run: Functional Chain of Responsibility implementation in Scala</a>
    </li>
  </ul>

  <p>
    以下の二つは関数型パラダイムでのデザインパターンにもなりえると思う.
  </p>

  <ul class="org-ul">
    <li>
      Decorator Pattern
    </li>
    <li>
      Chain of Responsibility Pattern
    </li>
  </ul>
</div>

07 Dec 2014, 12:45

Haskell の xUnit ツール HUnit を試す

はじめに

Haskell でテストコードを書くツールをしらべてみた.

メジャーなものは以下

  • doctest
  • QuickCheck
  • HSpec
  • HUnit

各ツールの特徴

doctest

コメントにテストを書くスタイルのツール.

Python の doctest を haskell に移植したものだとか.

QuickCheck

ランダムなテストデータによって関数の性質をテストする.

xUnit とは異なるコンセプトをもつ.

HSpec

xSpec ライクなテストツール.

Ruby の RSpec にインスパイヤされたらしい.

記法が BDD 的.

HUnit

xUnit ライクなテストツール. JUnit ライク.

HUnit を試す

JUnit になじみがあるので, HUnit を試してみた.

Install

$ cabal install HUnit

Usage

Test.HUnit をインポート.

import Test.HUnit

テスト対象コード

import Data.List
import Data.Char
import Unsafe.Coerce

data Nat = Zero
         | Succ Nat
         deriving Show

natToInteger (Succ n) = natToInteger n + 1
natToInteger Zero = 0

テストコード

tests = TestList
        [ "natToInteger 1" ~: natToInteger Zero ~?= 0
        , "natToInteger 2" ~: natToInteger (Succ Zero) ~?= 1
        , "natToInteger 3" ~: natToInteger (Succ (Succ Zero)) ~?= 2
        ]

テスト実行

runTestTT (テスト関数名) でテスト実行.

$ runTestTT tests
Cases: 3  Tried: 3  Errors: 0  Failures: 0
Counts {cases = 3, tried = 3, errors = 0, failures = 0}

わざと失敗させてみる.

*Main> runTestTT tests
### Failure in: 2:natToInteger 3
expected: 1
 but got: 2
Cases: 3  Tried: 3  Errors: 0  Failures: 1
Counts {cases = 3, tried = 3, errors = 0, failures = 1}

Bookmarks

07 Dec 2014, 11:32

Java におけるポリモーフィズムの整理

はじめに

Haskell で型クラスというものを勉強した.

その延長で, 今までとてもいい加減に理解していた Java のポリモーフィズムについて再度復習した.

なんか, 用語の関係性をすごく曖昧に理解していた気がした.

Polymophism: 多相性

各要素 (定数, 変数, 式, オブジェクト, 関数, メソッドなど) についてそれらが複数の型に属することを許すという性質.

同種のクラスをカテゴリに分類してまとめ, 基本的な動作・設計部分を統一することで, オブジェクトインスタンスの扱いに柔軟性と規律を持たせるための機能.

多相性は 3 つに分類できる.

  • アドホック多相:
  • パラメータ多相:
  • サブタイプ多相:

たとえば Java だと以下に相当する.

  • アドホック多相: オーバーロード
  • パラメータ多相: ジェネリクス
  • サブタイプ多相: 継承, インタフェース

参考:

Polymorphic Type: 多相型

<div class="outline-text-3" id="text-unnumbered-3">
  <p>
    データ構造のコンテナ.
  </p>

  <p>
    データ形式に依存しないコンピュータプログラミング方式をジェネリクス プログラミングという.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AA%E3%83%83%E3%82%AF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0">ジェネリックプログラミング &#8211; Wikipedia</a>
    </li>
  </ul>
</div>

アドホック多相

オブジェクト指向におけるアドホック多相とは, オーバーロードに相当する. 多重定義ともいう.

パラメータ多相

型変数

<div class="outline-text-3" id="text-unnumbered-6">
  <p>
    多相型は宣言されたクラス, 関数に対して, 利用時に具体的な型を与える. これを型変数 (Type variable) という.
  </p>

  <p>
    Java の名前つけルールがあるらしい.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://java.keicode.com/lang/generics-naming.php">名前付けルール &#8211; Java 入門</a>
    </li>
  </ul>
</div>

Generic Type: 総称型

<div class="outline-text-3" id="text-unnumbered-7">
  <p>
    型付けされたプログラミング言語において データ型の定義とそれを参照する式 (型式) の一部にパラメタを許すことによって 類似した構造を持つ複数のデータ型を一括して定義して, それらを選択利用する仕組み.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E7%B7%8F%E7%A7%B0%E5%9E%8B">総称型 &#8211; Wikipedia</a>
    </li>
  </ul>

  <p>
    オーバーロード (overload), 継承 (inheritance) と並んでプログラミング言語において ポリモーフィズムを実現するための一つの手段.
  </p>
</div>

言語ごとの実現方法

<div class="outline-text-3" id="text-unnumbered-8">
  <ul class="org-ul">
    <li>
      Java: ジェネリクス, ワイルドカード <ul class="org-ul">
        <li>
          <a href="http://futurismo.biz/archives/2750">Java でのジェネリックスの使い方まとめ | Futurismo</a>
        </li>
      </ul>
    </li>

    <li>
      C++: テンプレート
    </li>
    <li>
      Haskell: <ul class="org-ul">
        <li>
          リスト
        </li>
        <li>
          タプル
        </li>
        <li>
          Either
        </li>
        <li>
          Maybe
        </li>
      </ul>
    </li>
  </ul>
</div>

Subtyping: 派生型

データ型 S が他のデータ型 T と is-a 関係にあるとき, S を T の派生型 (はせいがた, subtype) であるという.

基本型のデータを処理するように作られたプログラムは, その派生型のデータでも正しく処理することができる.

基本型-派生型関係ではリスコフの置換原則 (Liskov Substitution Principle) が成り立つ.

2 つの方法がある

  • インタフェース: 型をグループで分類
  • 継承: 型を階層構造で分類

inheritance: 継承

<div class="outline-text-3" id="text-unnumbered-10">
  <p>
    ほとんどのクラスベースオブジェクト指向言語では, サブクラス (インヘリタンス) が派生型の概念を実現している.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E7%B6%99%E6%89%BF_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)">継承 (プログラミング) &#8211; Wikipedia</a>
    </li>
  </ul>
</div>

override: オーバーライド

<div class="outline-text-3" id="text-unnumbered-11">
  <p>
    オブジェクト指向プログラミングにおいてオーバーライド (override) とは, スーパークラスで定義されたメソッドをサブクラスで定義しなおし, 動作を上書きすること.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC%E3%83%A9%E3%82%A4%E3%83%89">オーバーライド &#8211; Wikipedia</a>
    </li>
  </ul>
</div>

interface: インタフェース

<div class="outline-text-3" id="text-unnumbered-12">
  <p>
    抽象データ型のメソッド.
  </p>

  <p>
    Object 型を分類し, 同じカテゴリに属するクラスに共通のインターフェイスを取り決める.
  </p>

  <p>
    implements ステートメントは, クラスたちのカテゴリ分類を明確にする方法.
  </p>

  <p>
    変数の型としてカテゴリクラスを指定すると, そのカテゴリを Implements したクラス (つまり, カテゴリに属するクラス) のインスタンスも格納できるようになる.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://homepage1.nifty.com/CavalierLab/lab/vb/clsmdl/polymorphism_02.html">ポリモーフィズムとインターフェイス</a>
    </li>
  </ul>

  <p>
    オブジェクトが, 共通のインターフェイスを実装している場合, 他のオブジェクトに置き換えることができる.
  </p>
</div>

<div id="outline-container-unnumbered-13" class="outline-4">
  <h4 id="unnumbered-13">
    どう分類するか?: 共通性/ 可変性 分析法
  </h4>

  <div class="outline-text-4" id="text-unnumbered-13">
    <p>
      オブジェクト指向のこころより引用.
    </p>

    <ul class="org-ul">
      <li>
        共通性分析:時間が経っても変化しにくい構造を見つけるもの
      </li>
    </ul>

    <p>
      共通性分析によってまとめられた概念を抽象クラスによって表現
    </p>

    <ul class="org-ul">
      <li>
        可変性分析:変化しやすい構造を洗い出すもの
      </li>
    </ul>

    <p>
      可変性分析で得た流動的要素は抽象クラスの派生クラスによって実装される
    </p>

    <p>
      設計手順:
    </p>

    <ul class="org-ul">
      <li>
        (抽象クラス) このクラスが持つ責務をすべて全うするにはどうようなインターフェイスが必要か?
      </li>
      <li>
        (派生クラス) この特定実装の中でどうのようにして与えられた仕様を実装できるのか?
      </li>
      <li>
        共通性: 時がたっても変わらないものを抽象クラスに
      </li>
      <li>
        可変性: 流動的要素を具象クラスに.
      </li>
    </ul>

    <p>
      クラスの集合がもつすべての責務を真っ当するために, インタフェースを用意する.
    </p>

    <p>
      Jim Coplien が提唱. p235 第 15 章から抜粋.
    </p>

    <ul class="org-ul">
      <li>
        <a href="http://www.amazon.co.jp/%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%A8%E3%81%A8%E3%82%82%E3%81%AB%E5%AD%A6%E3%81%B6%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%AE%E3%81%93%E3%81%93%E3%82%8D-Software-patterns-%E3%82%A2%E3%83%A9%E3%83%B3%E3%83%BB%E3%82%B7%E3%83%A3%E3%83%AD%E3%82%A6%E3%82%A7%E3%82%A4/dp/4894716844">Amazon.co.jp: デザインパターンとともに学ぶオブジェクト指向のこころ (Software patterns series): アラン・シャロウェイ, ジェームズ・ R ・トロット, 村上 雅章: 本</a>
      </li>
    </ul>
  </div>
</div>

型クラス

<div class="outline-text-3" id="text-unnumbered-14">
  <p>
    Haskell の概念.
  </p>

  <ol class="org-ol">
    <li>
      型は値をグループ化する.
    </li>
    <li>
      型クラスは, 型をグループ化する.
    </li>
  </ol>

  <p>
    この説明はわかりやすい.
  </p>

  <ul class="org-ul">
    <li>
      値 < 型 < 型クラス
    </li>
    <li>
      <a href="http://jutememo.blogspot.jp/2009/05/haskell.html">Haskell のモジュールの階層化と, 型クラス &#8211; パラメータ多相とアドホック多相 | すぐに忘れる脳みそのためのメモ</a>
    </li>
  </ul>

  <p>
    型を分類する点でいえば, Java のインタフェースと同義.
  </p>
</div>

おわりに

先月くらいにクラス設計をしていたときに, 会社である怖い人が,

継承とは, オブジェクトを分類するための手段なんだ!

といっていたが, ようやくその意味を理解した気がした.

07 Dec 2014, 04:20

Java で プリミティブ型から byte 型配列へ変換する

はじめに

Java で byte 型を扱う方法を調べてみたのでまとめてみる.

ByteBuffer クラスをつかう

ByteBuffer クラスを利用すると, byte 型に対するいろいろな操作が簡単にできる.

他のプリミティブ型から byte 型配列 に変換

手順は以下.

  1. ByteBuffer.allocate (size) でメモリ獲得.
  2. putXXX メソッドで獲得したメモリに値を挿入
  3. array () で byte 配列に変換
ByteBuffer buffer = ByteBuffer.allocate (arraySize);
buffer = buffer.putXXXX (value)
byte[] bytes = buffer.array ();

Sample

import java.nio.ByteBuffer;

class ByteSample {

    public static void main (String args[]) {
        showBytes (short2Byte ((short) 10));
        showBytes (int2Byte (10));      
        showBytes (int2ByteN (10));
        showBytes (long2Byte (10L));        
    }

    public static byte[] short2Byte (short value) {
        return ByteBuffer.allocate (Short.SIZE/Byte.SIZE).putShort (value).array ();
    }

    public static byte[] int2Byte (int value) {
        return ByteBuffer.allocate (Integer.SIZE/Byte.SIZE).putInt (value).array ();
    }

    public static byte[] long2Byte (long value) {
        return ByteBuffer.allocate (Long.SIZE/Byte.SIZE).putLong (value).array ();
    }

    static void showBytes (byte[] bytes) {
        for (int i=0; i < bytes.length; i++)
            System.out.printf (Integer.toHexString (bytes[i] &0xff));           
        System.out.println ("");
    }
}

出力結果

0a
000a
0000000a

エンディアン対応

ByteBuffer の初期順序は, BIG_ENDIAN.

  • ビッグエンディアン

複数バイトのデータを上位バイトから順番に格納する方式です. 0x1234ABCD を 0x12,0x34,0xAB,0xCD という順番で保存します.

  • リトルエンディアン

複数バイトのデータを下位バイトから順番に格納する方式です. 0x1234ABCD を 0xCD,0xAB,0x34,0x12 という順番で保存します.

リトルエンディアン (ネットワークバイトオーダー) に対応するためには, java.nio.ByteOrder クラスと order メソッドを利用する.

public static byte[] int2ByteN (int value) {
    ByteBuffer byteBuffer = ByteBuffer.allocate (Integer.SIZE/Byte.SIZE);
    byteBuffer.order (ByteOrder.LITTLE_ENDIAN);
    byteBuffer.putInt (value);
    return byteBuffer.array ();
}

Bookmarks