ジェネリクスでタイプセーフなDAOモドキを作ってみた

クラス図はこんなの。


Hibernateとか使って,実際にDBに永続化してみればよかったんだけど,そこまで準備ができなかったので,なんちゃってコードで検証だけしてみた。


使い方は,こう。

private static void testCat() {
    CatDAO dao = new CatDAO();
    List<Cat> list = dao.findAll();
    for (Cat cat : list) {
        System.out.println("cat = " + cat);
    }
    Cat cat = dao.get();
    dao.save(cat);
}

いちおう思惑通りにはできたんじゃないかと思う。キャスト不要だし,IDEAとNetBeansのコードアシストでも,型変数が期待通りの値になったしね。


恥を忍んでコードを晒すことにする(なんちゃってだから細かいところは気にしちゃイカン)。まず,DAOの親玉。

public abstract class DAO<T> {
    private Class<T> _type_;

    protected DAO(Class<T> clazz) {
        _type_ = clazz;
    }

    public void save(T obj) {
        System.out.println("obj = " + obj);
    }

    public T get() {
        T obj = null;
        try {
            obj = _type_.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    public List<T> findAll() {
        List<T> list = new ArrayList<T>();
        for (int i = 0; i < 5; i++) {
            list.add(get());
        }
        return list;
    }
}

型変数:Tに対して「T.class」とかって書けないので,型変数と同じクラスをもらうことにしておいた。


次に,具象DAOのコード例(CatDAO)。

public class CatDAO extends DAO<Cat> {
    public CatDAO() {
        super(Cat.class);
    }
}

恐ろしく簡単。これでタイプセーフになるんだけど,ホントかどうか怪しんでしまうな。:-P


どうもジェネリクス・クラスはインスタンス作んないと型変数が有効にならんようなので,DAOがユーティリティ的であってもインスタンスは作る。
インスタンスの管理までは気にしてないけど,シングルトンにしたきゃ,そうすりゃいいし,インスタンス管理を今風にDIにまかせてもいい。
#まあ,なんとでもなるでしょ。


あと,たとえば具象DAOに独自のfinderメソッド作りたかったら,こんな風に作ればいい。

public class DogDAO extends DAO<Dog> {
    public DogDAO() {
        super(Dog.class);
    }

    public List<Dog> findXXX() { ... }
}

ジェネリクス,けっこう面白いぞ。:-D