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

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

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

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

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

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

Authors:Agata Toshitaka

ユーティリティクラス

 
イントロダクション
パターン解説
具体的な例
まとめ
 

イントロダクション

 ユーティリティクラスはデザインパターンではありませんが、良く使われる基本的な定石なのであえてここでご紹介いたします。
 ユーティリティクラスは、staticな共通の処理のメソッドを集めたクラスです。
 同じ処理が2箇所以上で出てきた場合は、ユーティリティクラスにまとめることができる可能性があります。
 ユーティリティクラスを使うと共通処理を1箇所にまとめることができますので、再利用性の向上ばかりでなく、あとから修正が発生してもユーティリティクラスの修正だけですみ、保守性が向上するというメリットがあります。
TOP

パターン解説

 ユーティリティクラスを作るのは簡単です。
 各クラスに点在する共通処理を、ユーティリティクラスのstaticメソッドに移動させるだけで、ユーティリティクラスの一丁あがりです。 ユーティリティクラスに移動した処理はどこからでも呼び出すことができます(図1〜2)。
図1 ユーティリティークラス適用前/適用後
図2 ユーティリティークラスのイメージ
TOP

具体的な例

◎第1段階:ユーティリティークラス未使用

 それではより具体的な例を見てみましょう。
 まずは、ユーティリティクラスを使用しない状態のコードから見ていきます(図3)。
図3 ユーティリティークラス未使用時のクラス図
 このサンプルWebアプリケーションでは、管理者が商品の価格の設定、変更処理を扱っています。
 SetPriceServletクラス(リスト1)は販売価格を新規に設定するサーブレットです。
 また、UpdatePriceServletクラス(リスト2)は販売価格を更新するサーブレットです。
リスト1 SetPriceServlet.java

/**
 * 販売価格をセットするサーブレットです。
 */
public class SetPriceServlet extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse res)
				throws ServletException, IOException {

		// 金額を取得する
		String priceStr = req.getParameter("price");
@
		// カンマと\記号を取り除く
		priceStr = priceStr.replaceAll(",", "");
		priceStr = priceStr.replaceAll("\\\\", "");

		// 数値に変換
		int price = Integer.parseInt(priceStr);
// 金額の新規セット // (省略) } }
リスト2 UpdatePriceServlet.java

/**
 * 販売価格を更新するサーブレットです。
 */
public class UpdatePriceServlet extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse res)
				throws ServletException, IOException {

		// 金額を取得する
		String priceStr = req.getParameter("update_price");

@
		// カンマと\記号を取り除く
		priceStr = priceStr.replaceAll(",", "");
		priceStr = priceStr.replaceAll("\\\\", "");

		// 数値に変換
		int price = Integer.parseInt(priceStr);
// 金額の修正処理 // (省略) } }
 Web画面では商品の金額を「¥1,000」のように¥記号とカンマを付けて入力します。 システム側では、入力された金額文字列から、¥記号とカンマを取り除いて、金額として扱う必要があります。
 ユーティリティクラスを使わずに素直に書くと、金額文字列の変換処理がリスト1-@リスト2-@のように重複してしまいます。 システムが大きくなり金額を入力する画面が増えると、重複箇所はさらに増えていくことでしょう。
 そこで「金額文字列」→「数値」の変換処理をユーティリティクラスに移動させます。
MEMO
priceStr.replaceAll("¥¥¥¥","")ってどういう意味?
 StringクラスのreplaceAll()メソッドでは、第1引数で指定した正規表現にマッチした文字列を、第2引数で指定した文字列に置換します。
 「¥¥¥¥」はJavaの文字列としては「¥¥」という意味になりますね。 さらに正規表現では「¥」が特別な意味を持ちますので、「¥¥」が¥記号を意味します。
 結果的にこのコードは「¥記号を空文字に変換しなさい」という意味になります。

◎第2段階:ユーティリティークラスの適用

 次にユーティリティクラス使用後のサンプルです(図4〜5)。
図4 ユーティリティークラス使用時のクラス図
図5 ユーティリティークラス使用時のシーケンス図
 文字列や数値を変換するユーティリティクラスとして、ConvertUtilクラス(リスト3)を作成しています。
リスト3 ConvertUtil.java

/**
 * 文字列や数値の変換を行うユーティリティークラスです。
 */
public class ConvertUtil {
@
	/**
	 * コンストラクタです。
	 * インスタンス化禁止です。
	 */
	private ConvertUtil() { }
A
	/**
	 * 金額文字列に含まれるカンマと\記号を取り除いて、数値に変換します。
	 * @param priceStr 金額文字列
	 * @return 変換後の金額
	 */
	public static int toPrice(String PriceStr) {
		priceStr = priceStr.replaceAll(",", "");
		priceStr = priceStr.replaceAll("\\\\\\", "");

		int price = Integer.ParseInt(priceStr);
		return price;
	}
}
 先ほどの重複コードは、リスト3-AのtoPrice()メソッドとして1箇所にまとめています。
 金額文字列を数値に変換する処理ですので、toPrice()メソッドの引数は金額文字列(String)で、戻り値は金額の数値(int)になります。
 各サーブレットでは、リスト4-@リスト5-@のようにConvertUtilのtoPrice()メソッドを呼び出すだけになりました。
リスト4 SetPriceServlet.java(ユーティリティークラス版)

/**
 * 販売価格をセットするサーブレットです。
 */
public class SetPriceServlet extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse res)
				throws ServletException, IOException {

		// 金額を取得する
		String priceStr = req.getParameter("price");

		// 数値に変換
		int price = ConvertUtil.toPrice(priceStr); …@

		// 金額の新規セット
		// (省略)
	}
}
リスト5 UpdatePriceServlet.java(ユーティリティークラス版)

/**
 * 販売価格を更新するサーブレットです。
 */
public class UpdatePriceServlet extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse res)
				throws ServletException, IOException {

		// 金額を取得する
		String priceStr = req.getParameter("update_price");

		// 数値に変換
		int price = ConvertUtil.toPrice(priceStr); …@

		// 金額の修正処理
		// (省略)
	}
}
 このようにたった3行の処理ですがユーティリティクラスに移動することで、保守性・再利用性が高いコードになりました。
 今後金額を入力する画面が増えても、変換処理はtoPrice()メソッドで処理できそうです。
 ユーティリティクラスは基本的にすべてのメソッドがstaticになりますので、インスタンス化する必要がありません。 そこでリスト3-@のようにコンストラクタをprivateにして、インスタンス化を禁止しています。
TOP

まとめ

◎ユーティリティクラスの対象となるもの

 共通処理ならばなんでもユーティリティクラスにすればよいわけではありません。 本来ならオブジェクトにしたほうがよいものをユーティリティクラスにすると、オブジェクト指向のメリットを生かせない、融通の利かないシステムになってしまいます。
 ではどのような処理をユーティリティクラスにすればよいのでしょうか?
 まず考えられるのは「状態を持たない処理」です。 具体例であげている変換処理は、「変換前のデータ」を渡すと「変換後のデータ」が手に入ればよく、状態を持つ必要はありませんでした。 このように、状態を保持し続ける必要がない処理はユーティリティクラス化に向いています。 また、単なる計算や関数などもユーティリティクラス向きです。  java.lang.Mathクラスはこの典型であるといえます。

◎業務固有のユーティリティクラス

 ユーティリティクラスはすべてのアプリケーションで共通に使用できる汎用的なものと、特定の業務アプリケーション固有の共通処理を行うものが考えられます。
 特定業務固有のユーティリティクラスは「アプリ名+Util(s)」という名前になることが多いようです。 例えば「DP」いうプロジェクトなら「DPUtils」といった具合です。

◎Jakarta Commonsはユーティリティクラスの宝庫

 JakartaプロジェクトのCommonsサブプロジェクト(http://jakarta.apache.org/commons/)はユーティリティクラスの宝庫です。
 Javaの標準APIにはない便利なメソッドを持つユーティリティクラスが数多く用意されています。 品質も高いのでこれらをうまく使わない手はありません。
 自分でユーティリティークラスを作る前に、「こんなユーティリティークラスないかな?」という気持ちで、まずはCommonsをチェックしてみるのもよいでしょう。
TOP