0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

クラス設計を意識して10進数から2~36進数に基数変換するプログラムを作成してみた (Java)

Last updated at Posted at 2025-07-09

作成経緯

クラス設計の学習ノート (Java) #1を前回投稿した.
前回投稿した内容が身についているかを確認するための演習として, 10進数から2~36進数に基数変換するプログラムを作成してみた.


クラス構造

  • BaseConverterは基数変換を行うプログラム (クラス)
  • ConvertAppはユーザーの入力制御・基数変換の流れを管理するクラス
  • BaseConvertはオブジェクト生成時に受け取った引数をもとに基数変換を行うクラス
  • InputUtilsは入力関連のクラス

各クラスのコード

BaseConverter.java

import java.util.Scanner;

/**
 * <h1>BaseConverter</h1>
 * <p>基数変換を行うプログラムです.</p>
 * <p>ユーザーから入力された0以上の整数を入力された基数 (2~36) で基数変換を行います.</p>
 * @since 2025-07-09~2025-07-10
 * @author space
 */
public class BaseConverter {
    // 区切り線
    private static final String SEPARATOR
            = "----------------------------------------------------------------------------";

    /**
     * mainメソッド
     * @param args 未使用
     */
    public static void main(String[] args) {
        // Scannerオブジェクトの生成 (try-with-resources)
        try (Scanner in = new Scanner(System.in)) {
            // ConvertAppオブジェクトの生成
            ConvertApp app = new ConvertApp(in);
            String isLoop;     // ループするかどうか (y/n)
            do {
                // 基数変換プログラムを1度実行
                app.run();
                // もう一度実行するかを尋ねる
                System.out.print("もう一度基数変換を行いますか?(y/n):");
                isLoop = in.next();     // 「y」or「Y」が入力されたらループ
                //区切り線の表示
                System.out.println(SEPARATOR);
            } while (isLoop.equalsIgnoreCase("y"));
        }
    }
}

ConverApp.java

import java.util.Scanner;

/**
 * ユーザー入力の制御・基数変換の流れを管理するクラス<br>
 * 本クラスでは外部で生成されたScannerを使用するが, Scannerクローズは生成元で行う必要がある
 * @since 2025-07-09~2025-07-13
 * @author space
 */
public class ConvertApp {
    // 変換元の整数入力の最小値
    private static final int INPUT_MIN = 0;
    // 基数の最小値 (10進数表記)
    private static final int BASE_MIN = 2;
    // 基数の最大値 (10進数表記)
    private static final int BASE_MAX = 36;

    // Scannerオブジェクト
    private final Scanner in;

    /**
     * InputUtilsオブジェクトを生成するコンストラクタ
     * @param in Scannerオブジェクト<br>
     *           Scannerクローズは生成元で行う必要がある
     */
    public ConvertApp(Scanner in) {
        this.in = in;
    }

    /**
     * ユーザー入力の制御・基数変換の流れを管理するメソッド<br>
     * 通称「基数変換プログラム」
     */
    public void run() {
        System.out.println("基数変換を行います!");

        // InputUtilsオブジェクトの生成
        InputUtils input = new InputUtils(in);

        // 変換元の整数の入力
        System.out.printf("%dから%dまでの変換元の整数を入力してください:", INPUT_MIN, Integer.MAX_VALUE);
        int num = input.inputIntInRange(INPUT_MIN, Integer.MAX_VALUE);
        // 変換後の基数の入力
        System.out.printf("%dから%dまでの変換後の基数を入力してください:", BASE_MIN, BASE_MAX);
        int base = input.inputIntInRange(BASE_MIN, BASE_MAX);

        // numをbase進数に変換するためのBaseConvertオブジェクトを生成
        BaseConvert convert = new BaseConvert(num, base);
        // radixをnumのbase進数表記で初期化
        String radix = convert.radixConverter();

        // 基数変換の結果を表示
        System.out.printf("%dを%d進数に変換 -----> %s\n", num, base, radix);
    }
}

BaseConvert.java

/**
 * オブジェクト生成時に受け取った引数をもとに基数変換を行うクラス
 * @since 2025-07-09~2025-07-13
 * @author space
 */
public class BaseConvert {
    // 底の最小値 (10進数表記)
    private static final int BASE_MIN = 2;
    // 底の最大値 (10進数表記)
    private static final int BASE_MAX = 36;
    // BASE_MAX進数の数字の情報
    private static final String[] BASES = new String[BASE_MAX];

    // クラスが初めて読み込まれたときに1度だけ実行する処理
    static {
        // 36進数の数字 (0~9, A~Z) をBASESの各インデックスの要素に格納
        for (int i = 0; i < BASES.length; i++) {
            BASES[i] = (i < 10)
                    ? String.valueOf(i)                         // 0~9 → "0"~"9"
                    : String.valueOf((char)('A' + i - 10));     // 10~35 → "A"~"Z"
        }
    }


    private final int num;            // 0以上の整数
    private final int base;           // 変換後の基数 (2~36の整数)

    /**
     * BaseConvertオブジェクトを生成するコンストラクタ<br>
     * BaseConvertオブジェクト生成時に36進数 (0~9, A~Z) の数字をBASESの各インデックスに格納
     * @param num 0以上の整数
     * @param base 変換後の基数 (2~36の整数)
     * @throws IllegalArgumentException パラメータ情報として指定されている範囲外の値が引数として渡されたときに発生する例外
     */
    public BaseConvert(int num, int base) {
        // 指定されている範囲外の値が引数として渡されたときの例外処理
        if (num < 0 || base < BASE_MIN || base > BASE_MAX) {
            throw new IllegalArgumentException("引数の値が不正です。");
        }
        // フィールドの初期化
        this.num = num;
        this.base = base;
    }

    /**
     * フィールドの情報をもとに基数変換を行うメソッド
     * @return 基数変換後の値 (文字列で返す)
     */
    public String radixConverter() {
        int value = num; // 状態を壊さないようコピー
        // 基数変換したものを格納するためのStringBuilder
        StringBuilder radix = new StringBuilder();
        // 各ビットを右から順に加えていく
        do {
            radix.insert(0, BASES[value % base]);
            value /= base;     // 基数で割って次の桁に進む
        } while (value > 0);
        return radix.toString();
    }
}

InputUtils.java

import java.util.InputMismatchException;
import java.util.Scanner;

/**
 * 入力関連のクラス<br>
 * 本クラスでは外部で生成されたScannerを使用するが, Scannerクローズは生成元で行う必要がある
 * @since 2025-07-09~2025-07-13
 * @author space
 */
public class InputUtils {
    // 入力エラー文
    private static final String INPUT_ERROR_MESSAGE
            = "不正な値が入力されました。%dから%dまでの整数で再度入力してください:";

    // Scannerオブジェクト
    private final Scanner in;

    /**
     * InputUtilsオブジェクトを生成するコンストラクタ
     * @param in Scannerオブジェクト<br>
     *           Scannerクローズは生成元で行う必要がある
     */
    public InputUtils(Scanner in) {
        this.in = in;
    }

    /**
     * 整数を入力させるメソッド<br>
     * 入力最小値~入力最大値の整数が入力されるまで再入力を促す
     * @param min 入力最小値
     * @param max 入力最大値
     * @return 入力された整数
     */
    public int inputIntInRange(int min, int max) {
        int num;        // 入力最小値~入力最大値の整数
        while (true) {
            try {
                num = in.nextInt();    // 整数の入力
                // 入力範囲外の整数が入力されたとき
                if (num < min || num > max)
                    System.out.printf(INPUT_ERROR_MESSAGE, min, max);    // エラーメッセージの表示
                else break;     // 入力範囲内の整数が入力されたらループを抜ける
            } catch (InputMismatchException e) {
                // int型でない値が入力されたとき
                System.out.printf(INPUT_ERROR_MESSAGE, min, max);    // エラーメッセージの表示
                in.nextLine();      // バッファクリア
            }
        }
        return num;
    }
}

実行例

基数変換を行います!
0から2147483647までの変換元の整数を入力してください:2147483647
2から36までの変換後の基数を入力してください:36
2147483647を36進数に変換 -----> ZIK0ZJ
もう一度基数変換を行いますか?(y/n):y
----------------------------------------------------------------------------
基数変換を行います!
0から2147483647までの変換元の整数を入力してください:35
2から36までの変換後の基数を入力してください:36
35を36進数に変換 -----> Z
もう一度基数変換を行いますか?(y/n):y
----------------------------------------------------------------------------
基数変換を行います!
0から2147483647までの変換元の整数を入力してください:36
2から36までの変換後の基数を入力してください:36
36を36進数に変換 -----> 10
もう一度基数変換を行いますか?(y/n):y
----------------------------------------------------------------------------
基数変換を行います!
0から2147483647までの変換元の整数を入力してください:65536
2から36までの変換後の基数を入力してください:16
65536を16進数に変換 -----> 10000
もう一度基数変換を行いますか?(y/n):y
----------------------------------------------------------------------------
基数変換を行います!
0から2147483647までの変換元の整数を入力してください:65535
2から36までの変換後の基数を入力してください:16
65535を16進数に変換 -----> FFFF
もう一度基数変換を行いますか?(y/n):y
----------------------------------------------------------------------------
基数変換を行います!
0から2147483647までの変換元の整数を入力してください:-1
不正な値が入力されました。0から2147483647までの整数で再度入力してください:2147483647
2から36までの変換後の基数を入力してください:28
2147483647を28進数に変換 -----> 4CLM98F
もう一度基数変換を行いますか?(y/n):y
----------------------------------------------------------------------------
基数変換を行います!
0から2147483647までの変換元の整数を入力してください:-2
不正な値が入力されました。0から2147483647までの整数で再度入力してください:9999999999999999999999999999999999999999999999999999999999999999
不正な値が入力されました。0から2147483647までの整数で再度入力してください:23.5
不正な値が入力されました。0から2147483647までの整数で再度入力してください:あはははは
不正な値が入力されました。0から2147483647までの整数で再度入力してください:28
2から36までの変換後の基数を入力してください:-1
不正な値が入力されました。2から36までの整数で再度入力してください:jie2
不正な値が入力されました。2から36までの整数で再度入力してください:036
28を36進数に変換 -----> S
もう一度基数変換を行いますか?(y/n):n
----------------------------------------------------------------------------

振り返り

できるようになったこと

  • 責務に応じてクラスを分割する設計
  • クラス間の依存関係を適切に設計
  • 役割に応じてアクセス修飾子を適切に使うこと
  • 「状態を持つクラス」と「処理だけ行うクラス」を分けて設計
  • mainメソッドは最小限に、他のクラスに仕事を委任する設計
    • 分かりやすい & 再利用しやすい設計に

今後の目標

継承やオーバーライド、ポリモーフィズムなどの学習をして自分のものにしていきたい

0
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?