第1章
はじめてのデザインパターン  

第2章
逆引きカタログ ロジック編

第3章
逆引きカタログ J2EE編

第4章
逆引きカタログ その他

第5章
デザインパターン適用の勘所

第5章 デザインパターン適用の勘所

Authors:Agata Toshitaka

ユーティリティクラスの適用

図3 サンプルのクラス図(その2)
M子:
「先輩できました(リスト2,リスト3)。 ユーティリティクラスを使ったらずいぶんすっきりしましたよ。 ユーティリティクラスの名前はUploadUtilにしました。」

リスト2 UploadUtil.java
/**
 * Jakarta Commons FileUploadのユーティリティークラスです。
 */
public class UploadUtil {
	private static final Log log = LogFactory.getLog(UploadUtil.class);
	public static FileItem getFileItem(List fileItems, String name) {
		for (Iterator iter = fileItems.iterator(); iter.hasNext();) {
			FileItem item = (FileItem) iter.next();
			if (item.getName().equals(name)) {
				return item;
			}
		}
		return null;
	}
	/**
	 * アイテムリストから指定されたフィールド名の値を取得します。
	 */
	public static String getParameter(List fileItems, String name) {
		return getFileItem(fileItems, name).getString();
	}
@
	/**
	 * リクエストをパースして、アイテムリストを取得します。
	 */
	public static List parseRequest(
				HttpServletRequest req, int maxFileSize)
				  throws FileUploadRuntimeException {
		FileUpload fileUpload = new FileUpload();
		fileUpload.setSizeMax(maxFileSize);
		try {
			return fileUpload.parseRequest(req);
A
		} catch (FileUploadException e) {
			log.error(e.getMessage(), e);
			throw new FileUploadRuntimeException(e);
		}
}
}

リスト3 FileUploadServlet2.java
/**
 * ファイルアップロードサーブレット(ユーティリティークラスの適用)です。
 */
public class FileUploadServlet2 extends HttpServlet {
	/** ファイルサイズの上限です。 */
	private static final int MAX_FILE_SIZE = 1000000; ・・・@
	protected void doPost(HttpServletRequest req, HttpServletResponse res)
				throws ServletException, IOException {
		// マルチパートデータを取得
		List fileItems = UploadUtil.parseRequest(req, MAX_FILE_SIZE);

		// 商品コードの取得
		String itemCode = UploadUtil.getParameter(fileItems, "code");

		// アップロードされたファイルの処理
		FileItem item = UploadUtil.getFileItem(fileItems, "file");
		String filename = item.getName();
		byte[] data = item.get();
A
		// ファイルが画像だった場合
		if ("item.jpg".equals(filename)) {
			ImageDao dao = new ImageDao();
			dao.update(itemCode, filename, data);
		// ファイルがinfo.txtだった場合
		} else if ("info.txt".equals(filename)) {
			InfoDao dao = new InfoDao();
			String info = new String(data, "Windows-31J");
			dao.update(itemCode, info);
		}
} }
O先輩:
「うん、かなりすっきりしたね。繰り返し似たようなコードを書いているなぁって思ったら、ユーティリティクラスにするとすっきりとした良いコードにできる場合が多いんだ。 別の場所からユーティリティクラスは再利用できるしね。」
M子:
「再利用といえば、リスト3-@から呼び出しているリスト2-@のparseRequest()メソッドは工夫しましたよ。 ファイルサイズの上限を呼び出し側から渡せるようにしてるので、別の場所で上限が変わっても大丈夫です。 あと、100000ってわかりにくいってT美チャンに言われたんで、MAX_FILE_SIZEっていう定数にしました。」
O先輩:
「素晴らしい・・・」
M子:
(嬉しそうに)「実はもう一個工夫したのが、リスト2-Aの例外処理なんですよ。 実行時例外を使っちゃいました。 FileUploadExceptionが発生する場所で例外をキャッチして、実行時例外FileUploadRuntimeExceptionに変換して投げなおしています。 呼び出す側ではcatchが必要なくなっていい感じです。」
O先輩:
「ちゃんと例外のロギングもやっているね、素晴らしい・・・」
M子:
「でも、もう1つ気になっているところがあるんですよ。 仕様書には「最終的にはファイル名のパターンは30パターンになります」って書いてあるんですけど、増えたときにリスト3-Aのif文がすごく長くなっちゃいそうで。」
O先輩:
「良いところに気づいたね。 この部分は「ファイルに対応した処理」共通のインタフェースを作って、「ファイル処理プラグイン」を作ればよいと思うんだ。 ファイル名に対応したプラグインをファクトリに作らせれば、if文をなくすこともできるはずだよ。 ちょっと一緒にやってみようか。」
M子:
「プラグインかぁ。なんだかかっこいいですね。はい。お願いします。」
O先輩:
「まずはif文の中身に注目してみよう。item.jpgとinfo.txtで処理に必要なデータってなんだろう?」
M子:
「商品コードとファイル名、あとファイルの中身のbyte配列です。」
O先輩:
「そうだね。その3つを引数にしたメソッドを持つインタフェースを作ってみよう。」
M子:
「わかりました。やってみます。」
TOP