top / index / prev / next / target / source
日記形式でつづる いがぴょんコラム ウェブページです。
プロのJavaプログラマーのなかには、デザインパターンを適用したがる人がいます。(デザインパターン魔 という用語を 思い浮かべる方もいらっしゃることでしょう)
2007.07.05執筆
プロのJavaプログラマーのなかには、デザインパターンを適用したがる人がいます。(デザインパターン魔 という用語を 思い浮かべる方もいらっしゃることでしょう)
※注意: ここで挙げている例は ブラックユーモアです。
まず、「学校における数遊びゲームのルール」という抽象的な概念を抽出するという おこないを実施してみましょう。 FizzBuzzPattern01GameRule.java
/**
* どこかの学校の子供たちの遊び
*/
public interface FizzBuzzPattern01GameRule {
/**
* 与えられた数に対応する 特定のゲームにおけるメッセージを取得する。
*
* @param argNumber
* 対象となる数。
* @return 特定のゲームにおけるメッセージ。
*/
public String getMessage(final int argNumber);
}
イギリスの学校の子供たちの遊び FizzBuzzは 数字を使った遊びの一つとして インタフェースを実装します。 FizzBuzzPattern01Rule.java
/**
* FizzBuzz: イギリスの学校の子供たちの遊び
*
* 1から100までの数を取得する。<br>
* ・3の倍数のときは数の代わりに「Fizz」を取得する。<br>
* ・5の倍数のときは数の代わりに「Buzz」を取得する。<br>
* ・3と5両方の倍数の場合には数の代わりに「FizzBuzz」を取得する。
*/
public class FizzBuzzPattern01Rule implements FizzBuzzPattern01GameRule {
/**
* 与えられた数に対応する FizzBuzzメッセージを取得する。
*
* ・3の倍数のときは「Fizz」を戻す。<br>
* ・5の倍数のときは「Buzz」を戻す。<br>
* ・3と5両方の倍数の場合には「FizzBuzz」を戻す。<br>
* ・いずれにも該当しない場合には数を戻す。
*
* @param argNumber
* 対象となる数。
* @return メッセージ。
* 3の倍数のときは「Fizz」、5の倍数のときは「Buzz」、3と5両方の倍数の場合には「FizzBuzz」、いずれにも該当しない場合には数。
*/
public String getMessage(final int argNumber) {
// 3の倍数であるかどうか。
final boolean isMultipleOf3 = (argNumber % 3 == 0);
// 5の倍数であるかどうか。
final boolean isMultipleOf5 = (argNumber % 5 == 0);
if (isMultipleOf3 && isMultipleOf5) {
// 3と5両方の倍数の場合には「FizzBuzz」を戻す。
return "FizzBuzz";
} else if (isMultipleOf3) {
// 3の倍数のときは数の代わりに「Fizz」を戻す。
return "Fizz";
} else if (isMultipleOf5) {
// 5の倍数のときは「Buzz」を戻す。
return "Buzz";
} else {
// いずれにも該当しない場合には数を戻す。
return String.valueOf(argNumber);
}
}
}
ルールを利用する際には インスタンス生成の実行コストを考慮し、ループの外側でインスタンスを生成するようにします。 FizzBuzzPattern01.java
/**
* FizzBuzz: イギリスの学校の子供たちの遊び
*
* 1から100までの数をプリントする。<br>
* ・3の倍数のときは数の代わりに「Fizz」とプリントする。<br>
* ・5の倍数のときは数の代わりに「Buzz」とプリントする。<br>
* ・3と5両方の倍数の場合には数の代わりに「FizzBuzz」とプリントする。
*/
public class FizzBuzzPattern01 {
/**
* エントリポイント。
*
* @param args
* コマンドライン引数。このプログラム内では利用されない。
*/
public static void main(final String[] args) {
new FizzBuzzPattern01().process();
}
/**
* このクラスの主処理。
*/
public void process() {
// TODO:ゲームのルールを別に分け、またインタフェースを抽出しました。
final FizzBuzzPattern01GameRule rule = new FizzBuzzPattern01Rule();
for (int number = 1; number <= 100; number++) {
// 生成された文字列をプリントする。
System.out.println(rule.getMessage(number));
}
}
}
インタフェースを導出し、ここで満足するプログラマーがいます。
何かしらデザインパターン適用などによるリファクタリングを実施しおわると、次に他に適用可能なデザインパターンを探すのが習性という Javaプログラマーがいます。
ここではファクトリクラスを導入してみましょう。 FizzBuzzPattern02GameRuleFactory.java
/**
* 学校の子供たちの遊びを取得するファクトリクラス。
*/
public class FizzBuzzPattern02GameRuleFactory {
/**
* FizzBuzzゲームルールを取得する。
*
* @return ゲームルール。
*/
public static FizzBuzzPattern02GameRule getFizzBuzzRuleInstance() {
return FizzBuzzPattern02Rule.getInstance();
}
}
インタフェースのクラスは 特に変化ありません。 FizzBuzzPattern02GameRule.java
/**
* どこかの学校の子供たちの遊び
*/
public interface FizzBuzzPattern02GameRule {
/**
* 与えられた数に対応する 特定のゲームにおけるメッセージを取得する。
*
* @param argNumber
* 対象となる数。
* @return 特定のゲームにおけるメッセージ。
*/
String getMessage(final int argNumber);
}
ファクトリからインスタンスを取得するので、本体のコンストラクタは隠蔽化しておきます。 FizzBuzzPattern02Rule.java
/**
* FizzBuzz: イギリスの学校の子供たちの遊び
*
* 1から100までの数を取得する。<br>
* ・3の倍数のときは数の代わりに「Fizz」を取得する。<br>
* ・5の倍数のときは数の代わりに「Buzz」を取得する。<br>
* ・3と5両方の倍数の場合には数の代わりに「FizzBuzz」を取得する。
*/
public class FizzBuzzPattern02Rule implements FizzBuzzPattern02GameRule {
/**
* コンストラクタを隠蔽化する。
*/
private FizzBuzzPattern02Rule() {
}
/**
* このクラスのインスタンスを取得する。
*
* @return 新規に作成されたインスタンス。
*/
static FizzBuzzPattern02GameRule getInstance() {
return new FizzBuzzPattern02Rule();
}
/**
* 与えられた数に対応する FizzBuzzメッセージを取得する。
*
* ・3の倍数のときは「Fizz」を戻す。<br>
* ・5の倍数のときは「Buzz」を戻す。<br>
* ・3と5両方の倍数の場合には「FizzBuzz」を戻す。<br>
* ・いずれにも該当しない場合には数を戻す。
*
* @param argNumber
* 対象となる数。
* @return メッセージ。
* 3の倍数のときは「Fizz」、5の倍数のときは「Buzz」、3と5両方の倍数の場合には「FizzBuzz」、いずれにも該当しない場合には数。
*/
public String getMessage(final int argNumber) {
// 3の倍数であるかどうか。
final boolean isMultipleOf3 = (argNumber % 3 == 0);
// 5の倍数であるかどうか。
final boolean isMultipleOf5 = (argNumber % 5 == 0);
if (isMultipleOf3 && isMultipleOf5) {
// 3と5両方の倍数の場合には「FizzBuzz」を戻す。
return "FizzBuzz";
} else if (isMultipleOf3) {
// 3の倍数のときは数の代わりに「Fizz」を戻す。
return "Fizz";
} else if (isMultipleOf5) {
// 5の倍数のときは「Buzz」を戻す。
return "Buzz";
} else {
// いずれにも該当しない場合には数を戻す。
return String.valueOf(argNumber);
}
}
}
すると、ゲームのルールが変わっても 容易に切り替えを実現可能なクラスが出来上がります! FizzBuzzPattern02.java
/**
* FizzBuzz: イギリスの学校の子供たちの遊び
*
* 1から100までの数をプリントする。<br>
* ・3の倍数のときは数の代わりに「Fizz」とプリントする。<br>
* ・5の倍数のときは数の代わりに「Buzz」とプリントする。<br>
* ・3と5両方の倍数の場合には数の代わりに「FizzBuzz」とプリントする。
*/
public class FizzBuzzPattern02 {
/**
* エントリポイント。
*
* @param args
* コマンドライン引数。このプログラム内では利用されない。
*/
public static void main(final String[] args) {
new FizzBuzzPattern02().process();
}
/**
* このクラスの主処理。
*/
public void process() {
// TODO:ゲームのルールをファクトリクラスから取得するように変更しました。
final FizzBuzzPattern02GameRule rule = FizzBuzzPattern02GameRuleFactory
.getFizzBuzzRuleInstance();
for (int number = 1; number <= 100; number++) {
// 生成された文字列をプリントする。
System.out.println(rule.getMessage(number));
}
}
}
デザインパターンを適用し、ここで満足するプログラマーがいます。しかし これで飽きたらず また違うアイデアが次々に浮かんでくるものです。
MVC分離を検討する。 ※実のところ、私は 真っ先にMVC分離を思いつきました。コンソール版以外に Swing版や SWT版などを実装するのです!
DI/AOPによる実装を検討する。
EJBによる実装を検討する。
他のデザインパターン適用を もっともっと検討して実現する。
FizzBuzz程度の規模でも (デザインパターン魔は) デザインパターンを適用してしまいそうになるものなのです。
関連する日記