読者です 読者をやめる 読者になる 読者になる

似非プログラマのうんちく

「似非プログラマの覚え書き」出張版

MyBatis + Guice でカンタン DAO 実装(その 2)

前回の続き。

DAO 層の実装(続き)

まずは DAO クラスであることを明示するためのインターフェースを用意*1する。

package jp.mydns.akanekodou.dao.util;

import java.util.List;

/**
 * DAO クラス共通インターフェース
 *
 * @author Red cat
 * @param <T> DAO で扱うモデルクラス
 * @version 1.0
 */
public interface Dao<T> {
    /**
     * 全件取得
     *
     * @return 全データのリスト
     */
    List<T> all();
}

このインターフェースを実装して、実際の DAO を作る。

package jp.mydns.akanekodou.dao;

import com.google.inject.Inject;

import java.util.List;

import jp.mydns.akanekodou.bean.City;
import jp.mydns.akanekodou.dao.mapper.CityMapper;
import jp.mydns.akanekodou.dao.util.Dao;

/**
 * City 用 DAO クラス
 *
 * @author Red cat
 * @version 1.0
 */
public class CityDAO implements Dao<City> {
    @Inject
    private CityMapper mapper;

    /**
     * 全件取得
     *
     * @return City の全データのリスト
     * @see jp.mydns.akanekodou.dao.util.Dao#all()
     */
    @Override
    public List<City> all() {
        return mapper.all();
    }

    /**
     * 主キーを指定して 1 件取得
     *
     * @param id 主キー
     * @return 指定した主キーを持つ City のデータ
     */
    public City find(int id) {
        return mapper.find(id);
    }
}

@Inject アノテーションが付与されたフィールドは、Guice 経由でインスタンス化するときに設定ファイルに従って自動的にインジェクションされる。

一見して CityMapper と同じ処理をしていて冗長に見えるが、この方が DAO が SQL マッピングファイルから独立していて扱いやすいし、Guice 向けに見ても都合が良い。

最後に、DAO を Guice 経由でインスタンス化するためのユーティリティクラスを作る。

package jp.mydns.akanekodou.dao.util;

import org.mybatis.guice.XMLMyBatisModule;

import com.google.inject.Guice;
import com.google.inject.Injector;

/**
 * DAO 用ユーティリティクラス
 *
 * @author Red cat
 * @version 1.0
 */
public class DaoUtil {
    private Injector injector;
    // Singleton として実装
    private static DaoUtil inst = new DaoUtil();

    private DaoUtil() {
        injector = Guice.createInjector(new XMLMyBatisModule() {
            @Override
            protected void initialize() {}
        });
    }

    /**
     * DAO クラスのインスタンス取得
     *
     * @param clazz DAO クラス
     * @return DAO クラスのインスタンス
     */
    public static <T extends Dao<?>> T getDao(Class<T> clazz) {
        return inst.injector.getInstance(clazz);
    }
}

DAO クラスが Dao インターフェースを実装するように作ったのは、getDao の引数に DAO でないクラスが渡せないようにしたかったから。従って Dao インターフェースを実装していないクラスを引数に渡すとエラーになる。

実際に使うときは

CityDAO dao = DaoUtil.getDao(CityDAO.class);

のように書いて、CityDAOインスタンスGuice 経由で取得する。

*1:ポリモーフィズムよりも、DAO であることを明示する意味合いを重視しているので、正しいインターフェースの使い方とは言えないかも知れない。