Java

Javaで学ぶクラスの使い方とメリット|買い物プログラム実践解説

勉強ちゃん

前回は、商品名と数量を入力し、ファイルから単価を読み込んで合計金額を計算・保存するプログラムを作りました。
ただし、すべての処理を1つのmainに詰め込みだったので、読みづらく、拡張もしにくい状態でした。
今回はその続き、Javaの「クラス」とオブジェクトをわかりやすく解説しつつ、コードをクラス設計 → リファクタリングしていきます。

クラスとは

定義

クラス(class)は、アプリで扱うデータ(フィールド)と振る舞い(メソッド)をひとまとめにした設計図です。
設計図から実体化したものがオブジェクトインスタンス)です。
例)「商品」を表すクラス = 商品名 と 単価(データ)+ 合計を計算(振る舞い)

どうして必要

  • 再利用性:一度作ったクラスは、他のプログラムでもそのまま使えます。毎回ゼロから書く必要がないメリットがあります。
  • 見通しUP:入力・計算・保存などの処理をバラバラにせず、役割ごとにまとめられるので、コードがスッキリして見やすくなります。
  • 変更に強い:仕様変更や新しい機能を追加するとき、関係するクラスだけ直せばOK。他の部分に影響が少ないです。
  • バグ発生率低減:データ(商品名・値段など)と、そのデータを扱う処理を一緒にまとめられるので、間違いが起きにくくなります。

具体的例で説明(前回の買い物プログラムを分解して分析)

前回の処理は1つのmainにまとまっていました。実は次の4つの役割が混ざっています。

  1. 価格表の読み込み(ファイル → Map<String, Integer>
  2. ユーザー入力(商品名・数量)
  3. 計算(合計金額・明細生成)
  4. 結果の保存(ファイルへ出力)

→ それぞれを専用クラスに分けると、役割が明確になり保守が楽になります。

1 買い物・単価をクラス化

// 商品単価クラス
public class Item {
    private final String name;
    private final int unitPrice;

    public Item(String name, int unitPrice) {
        this.name = name;
        this.unitPrice = unitPrice;
    }
    public String getName() { return name; }
    public int getUnitPrice() { return unitPrice; }
}

2 商品明細・当該商品の合計の計算をクラス化

// 購入明細クラス(商品+数量+小計)
public class Purchase {
    private final Item item;
    private final int quantity;

    public Purchase(Item item, int quantity) {
        this.item = item;
        this.quantity = quantity;
    }
    public Item getItem() { return item; }
    public int getQuantity() { return quantity; }
    public int getSubtotal() { return item.getUnitPrice() * quantity; }

    // ファイル出力向けの1行表現
    public String toLine() {
        return item.getName() + "\t" + quantity + "\t" + getSubtotal() + "円";
    }
}

ポイント

  • 「商品(Item)」と「購入明細(Purchase)」を分けることで、データの意味が明確にします。
  • 計算をPurchaseに任せて、計算ロジックを共通化

3 買い物プログラムをリファクタリング

リファクタリングとは
外側の動作(入出力の結果)は変えず
、内部構造を整理・改善することです。
目的は可読性・保守性・拡張性の向上です。

  • ProductLoader:価格表ファイルの読み込み(productUnitPrice
  • ShoppingCalculator:ユーザー入力 → 明細生成&合計計算
  • ResultWriter:明細と合計金額をファイル出力(productInfo
  • Main:全体の流れを処理

3-1 価格表の読み込みをクラス化:ProductLoader

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

public class ProductLoader {
    // ファイル形式例: リンゴ,100 のような「商品名,単価」
    public Map<String, Integer> loadPrices(String fileName) throws IOException {
        Map<String, Integer> priceMap = new HashMap<>();
        try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
            String line;
            int row = 0;
            while ((line = br.readLine()) != null) {
                row++;
                if (line.isBlank()) continue;
                String[] data = line.split(",");
                if (data.length != 2) {
                    throw new IOException("価格ファイルの形式エラー(" + row + "行目): " + line);
                }
                String name = data[0].trim();
                int price = Integer.parseInt(data[1].trim());
                priceMap.put(name, price);
            }
        }
        return priceMap;
    }
}

3-2 入力と計算をクラス化:ShoppingCalculator

import java.util.*;

public class ShoppingCalculator {
    private final List<Purchase> lines = new ArrayList<>();
    private int total = 0;

    public void inputAndCalculate(Map<String, Integer> priceMap) {
        try (Scanner sc = new Scanner(System.in)) {
            while (true) {
                System.out.print("商品名を入力してください(終了は end):");
                String productName = sc.nextLine().trim();
                if ("end".equalsIgnoreCase(productName)) break;

                Integer unitPrice = priceMap.get(productName);
                if (unitPrice == null) {
                    System.out.println("指定された商品は存在しません。");
                    continue;
                }

                System.out.print("数量を入力してください: ");
                while (!sc.hasNextInt()) {
                    System.out.print("整数で入力してください: ");
                    sc.next();
                }
                int quantity = sc.nextInt();
                sc.nextLine(); // 改行の読み飛ばし

                Item item = new Item(productName, unitPrice);
                Purchase line = new Purchase(item, quantity);
                lines.add(line);
                total += line.getSubtotal();

                System.out.println("追加: " + line.toLine());
            }
        }
    }

    public List<Purchase> getLines() { return Collections.unmodifiableList(lines); }
    public int getTotal() { return total; }
}

3-3 結果の書き込みをクラス化:ResultWriter

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

public class ResultWriter {
    public void write(String fileName, List<Purchase> lines, int total) throws IOException {
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(fileName, true))) {
            for (Purchase line : lines) {
                bw.write(line.toLine());
                bw.newLine();
            }
            bw.write("合計金額:" + total);
            bw.newLine();
        }
    }
}

3-4 全体の流れ:Main

public class Main {
    public static void main(String[] args) {
        try {
            // 1) 単価表を読み込む
            ProductLoader loader = new ProductLoader();
            var priceMap = loader.loadPrices("productUnitPrice"); // 例: Apple,120

            // 2) 入力と計算
            ShoppingCalculator calculator = new ShoppingCalculator();
            calculator.inputAndCalculate(priceMap);

            // 3) 結果を保存
            ResultWriter writer = new ResultWriter();
            writer.write("productInfo", calculator.getLines(), calculator.getTotal());

            System.out.println("計算結果を productInfo に保存しました。");
        } catch (Exception e) {
            System.out.println("エラーが発生しました: " + e.getMessage());
        }
    }
}

クラス化のメリット

  • 保守性:どこを直せばよいか一目瞭然です。
  • 再利用性:ファイル読み込み・書き込み・入力処理を他プロジェクトでも使い回します。
  • テスト容易性ProductLoaderだけ、ResultWriterだけ、と単体テストがしやすいです。
  • 拡張性:「JSONの価格表にしたい」「GUI入力にしたい」「税計算を追加」など仕様変更に強いです。

まとめ

  • クラスはデータと処理をまとめる設計図。実体化がオブジェクトです。
  • 前回のプログラムは「入力・計算・入出力」が1か所に混在 → クラス分割で役割を明確化です。
  • リファクタリング後は読みやすい・変更しやすい・テストしやすい構造にしました。

次回

「クラスとオブジェクト」をさらに進めてスレッド(並行処理)入門への橋渡し
を予定しています。

ABOUT ME
自己紹介
自己紹介
職業:Web開発エンジニア
こんにちは!
このブログでは、ITのお仕事で学んだ知識や、 日本での生活で学んだ知識を紹介しています。
お役に立てればうれしいです 😊
記事URLをコピーしました