top / index / prev / next / target / source

2007-07-02 diary: FizzBuzz 問題 - ノーマル版

いがぴょんの日記 日記形式でつづる いがぴょんコラム ウェブページです。

old-v2

FizzBuzz 問題 - ノーマル版

「Fizz-Buzz問題」というものの存在を知り、ちょっと試してみました。

FizzBuzz 問題 - ノーマル版

2007.07.05執筆

「Fizz-Buzz問題」というものの存在を知り、少し興味を感じました。

ちょっと試しに Javaで作ってみました。なお、今回つくってみたのは「ノーマル版」です。しかも作成途中で 一旦作業を止めてしまいます。(続きは FizzBuzz 問題 - リファクタリング版 に書きます)

回答を作成する過程

普通の業務アプリケーションを Javaで作成する場合において、まず最初に JavaDoc から記載していく、というプログラミングの進め方が一般的です。プロの業務アプリケーションプログラマは、JavaDocに 最初から仕様をなるべく正しく書いておくように心がけるものです。

ああ、JavaDoc記述だけで 2分が過ぎてしまうような気がします。

JavaDocの記載が終わったら、次に 仕様を少しずつ実装していきます。ここでは「1から100までの数をプリントする。」という仕様のみを まず実装してみました。 FizzBuzzNormal01.java

/**
 * FizzBuzz: イギリスの学校の子供たちの遊び
 * 
 * 1から100までの数をプリントする。<br>
 * ・3の倍数のときは数の代わりに「Fizz」とプリントする。<br>
 * ・5の倍数のときは数の代わりに「Buzz」とプリントする。<br>
 * ・3と5両方の倍数の場合には数の代わりに「FizzBuzz」とプリントする。
 */
public class FizzBuzzNormal01 {
        /**
         * エントリポイント。
         * 
         * @param args
         *            コマンドライン引数。このプログラム内では利用されない。
         */
        public static void main(final String[] args) {
                // FIXME:まず「1から100までの数をプリントする。」のみを実装しました。それ以外の処理は実装されていません。
                for (int number = 1; number <= 100; number++) {
                        System.out.println(number);
                }
        }
}

※注意: このソースコードは、まだ仕様を実装している途中の状態です。 次に、それ以外の 残りの仕様も実装していきましょう。なお、業務システムにおいては、仕様を なるべく忠実に そのまま ソースコードへと展開するように心がける という点が重要です。(15などという数値は導出しないのが基本です) FizzBuzzNormal02.java

/**
 * FizzBuzz: イギリスの学校の子供たちの遊び
 * 
 * 1から100までの数をプリントする。<br>
 * ・3の倍数のときは数の代わりに「Fizz」とプリントする。<br>
 * ・5の倍数のときは数の代わりに「Buzz」とプリントする。<br>
 * ・3と5両方の倍数の場合には数の代わりに「FizzBuzz」とプリントする。
 */
public class FizzBuzzNormal02 {
        /**
         * エントリポイント。
         * 
         * @param args
         *            コマンドライン引数。このプログラム内では利用されない。
         */
        public static void main(final String[] args) {
                // TODO:「仕様通り」に実装しました。
                // TODO:マジックナンバーは追放されていません。
                // TODO:共通化が実施されていません。
                for (int number = 1; number <= 100; number++) {
                        // 3の倍数であるかどうか。
                        boolean isMultipleOf3 = false;
                        // 5の倍数であるかどうか。
                        boolean isMultipleOf5 = false;

                        if (number % 3 == 0) {
                                isMultipleOf3 = true;
                        }
                        if (number % 5 == 0) {
                                isMultipleOf5 = true;
                        }

                        if (isMultipleOf3 && isMultipleOf5) {
                                // 3と5両方の倍数の場合には「FizzBuzz」とプリントする。
                                System.out.println("FizzBuzz");
                        } else if (isMultipleOf3) {
                                // 3の倍数のときは数の代わりに「Fizz」とプリントする。
                                System.out.println("Fizz");
                        } else if (isMultipleOf5) {
                                // 5の倍数のときは「Buzz」とプリントする。
                                System.out.println("Buzz");
                        } else {
                                // 数をプリントする。
                                System.out.println(number);
                        }
                }
        }
}

倍数の判定部分が さすがに冗長に見えます。そのため、ここは変数の初期値としてセットするように変更します。この変更により実効行数を 6行ほど減らすことが出来ました。このような改善は 業務プログラミングにおいても普通に実施されます。 FizzBuzzNormal03.java

/**
 * FizzBuzz: イギリスの学校の子供たちの遊び
 * 
 * 1から100までの数をプリントする。<br>
 * ・3の倍数のときは数の代わりに「Fizz」とプリントする。<br>
 * ・5の倍数のときは数の代わりに「Buzz」とプリントする。<br>
 * ・3と5両方の倍数の場合には数の代わりに「FizzBuzz」とプリントする。
 */
public class FizzBuzzNormal03 {
        /**
         * エントリポイント。
         * 
         * @param args
         *            コマンドライン引数。このプログラム内では利用されない。
         */
        public static void main(final String[] args) {
                // TODO:倍数判定部分は、少しだけ短く書くこともできます。
                // TODO:マジックナンバーは追放されていません。
                // TODO:共通化が実施されていません。
                for (int number = 1; number <= 100; number++) {
                        // 3の倍数であるかどうか。
                        final boolean isMultipleOf3 = (number % 3 == 0);
                        // 5の倍数であるかどうか。
                        final boolean isMultipleOf5 = (number % 5 == 0);

                        if (isMultipleOf3 && isMultipleOf5) {
                                // 3と5両方の倍数の場合には「FizzBuzz」とプリントする。
                                System.out.println("FizzBuzz");
                        } else if (isMultipleOf3) {
                                // 3の倍数のときは数の代わりに「Fizz」とプリントする。
                                System.out.println("Fizz");
                        } else if (isMultipleOf5) {
                                // 5の倍数のときは「Buzz」とプリントする。
                                System.out.println("Buzz");
                        } else {
                                // 数をプリントする。
                                System.out.println(number);
                        }
                }
        }
}

いちおう、この時点で基本的な仕様は満たしています。しかし、自己ソースコードレビューをしていると、プリントする という仕様と 倍数の組み合わせ判定という仕様が 漫然と混在してしまっている点に気になってきます。これは シンプルさに欠けるように見えます。ほんの少しだけ共通化を進めてみます。 FizzBuzzNormal04.java

/**
 * FizzBuzz: イギリスの学校の子供たちの遊び
 * 
 * 1から100までの数をプリントする。<br>
 * ・3の倍数のときは数の代わりに「Fizz」とプリントする。<br>
 * ・5の倍数のときは数の代わりに「Buzz」とプリントする。<br>
 * ・3と5両方の倍数の場合には数の代わりに「FizzBuzz」とプリントする。
 */
public class FizzBuzzNormal04 {
        /**
         * エントリポイント。
         * 
         * @param args
         *            コマンドライン引数。このプログラム内では利用されない。
         */
        public static void main(final String[] args) {
                // TODO:一部共通化を実施しました。
                // TODO:マジックナンバーは追放されていません。
                for (int number = 1; number <= 100; number++) {
                        // 3の倍数であるかどうか。
                        final boolean isMultipleOf3 = (number % 3 == 0);
                        // 5の倍数であるかどうか。
                        final boolean isMultipleOf5 = (number % 5 == 0);

                        final StringBuffer bufMsg = new StringBuffer();
                        if (isMultipleOf3 && isMultipleOf5) {
                                // 3と5両方の倍数の場合には「FizzBuzz」とセットする。
                                bufMsg.append("FizzBuzz");
                        } else if (isMultipleOf3) {
                                // 3の倍数のときは数の代わりに「Fizz」とセットする。
                                bufMsg.append("Fizz");
                        } else if (isMultipleOf5) {
                                // 5の倍数のときは「Buzz」とセットする。
                                bufMsg.append("Buzz");
                        } else {
                                // 数をセットする。
                                bufMsg.append(number);
                        }

                        // 生成された文字列をプリントする。
                        System.out.println(bufMsg.toString());
                }
        }
}

ああ、なんとなく プロのレビューに耐えうる (可能性がある) プログラムのようになってきました。でも、まだ 本当のプロの Javaプログラマーにとっては気になるであろうところが多数見受けられます。つまり、この時点で これらソースコードは「作成途上の状態」と見なすことが出来ます。続きは FizzBuzz 問題 - リファクタリング版 に書いていきます。

関連する日記

BizzFuzz は TYPOです

2007.07.11追記 思わず BizzFuzz と入力してしまいそうになりました。でも、これは TYPO です。


この日記について