はじめてのオブジェクト指向~銀行口座システムを作って学ぼう!(コンソールアプリ版)~

🟡 0. このチュートリアルで学ぶこと

  • クラスとオブジェクトのちがいを体感する
  • 必要になるまでオブジェクトは作られないという実行の考え方を理解する
  • 複数人の口座管理をコードで体験する

🏦 1. 現実世界から考えてみよう

銀行で「田中太郎」が口座を作るとき、最初から口座があるわけではありません。

👉 申し込みをして「口座が開設された瞬間」から存在します。

オブジェクト指向でも同じです。


🧱 2. クラスを設計しよう(設計図)

public class BankAccount
{
    public string Owner { get; set; } = "";
    private int balance = 0;

    public void Deposit(int amount)
    {
        balance += amount;
    }

    public int GetBalance()
    {
        return balance;
    }
}

📌 この時点では、まだ口座は存在していません。

これは「設計図」にすぎません。


🟢 3. Visual Studio でプログラムを実行したとき…

🔸 よくある誤解:

「クラスを書いたらもうオブジェクトはあるんでしょ?」

🙅‍♂️ いいえ、それは設計図を書いただけです。


⏱ 4. 実行タイミングの本質(重要ポイント)

💥「実際の口座(オブジェクト)」ができるのはこの瞬間!

BankAccount taro = new BankAccount(); // ← この行で初めて口座が誕生!

Visual Studio で 【開始】Start ボタンを押さない限り、このコードは実行されません。

つまり、オブジェクト(口座)は存在しません!


🧰 5. 複数人の口座を管理してみよう

Dictionary<string, BankAccount> accounts = new();

この辞書に「名前」と「オブジェクト」を組み合わせて保存します。

var account = new BankAccount();
account.Owner = "佐藤花子";
accounts["佐藤花子"] = account;

🖥 6. Visual Studioで試してみよう

📦 補足資料:Visual Studio用サンプルコード一式

項目内容
ファイル名BankAccountSampleConsole_Multi.zip
含まれるものProgram.cs, BankAccount.cs(複数口座管理付き)
対応環境Visual Studio 2022(.NET 6以降)
ダウンロードリンクBankAccountSampleConsole_Multi.zip

🧾 7. 全体のコード

📄 BankAccount.cs

public class BankAccount
{
    public string Owner { get; set; } = "";
    private int balance;

    public void Deposit(int amount)
    {
        balance += amount;
    }

    public int GetBalance()
    {
        return balance;
    }
}

📄 Program.cs

using System;
using System.Collections.Generic;

internal class Program
{
    static Dictionary<string, BankAccount> accounts = new();

    static void Main(string[] args)
    {
        while (true)
        {
            Console.WriteLine("\n=== 銀行口座システム ===");
            Console.WriteLine("[1] 新しい口座を作成する");
            Console.WriteLine("[2] 入金する");
            Console.WriteLine("[3] 残高を確認する");
            Console.WriteLine("[4] すべての口座を表示");
            Console.WriteLine("[0] 終了");

            Console.Write("操作を選んでください: ");
            string input = Console.ReadLine()!;
            Console.WriteLine();

            switch (input)
            {
                case "1":
                    CreateAccount();
                    break;

                case "2":
                    Deposit();
                    break;

                case "3":
                    ShowBalance();
                    break;

                case "4":
                    ShowAllAccounts();
                    break;

                case "0":
                    Console.WriteLine("終了します。");
                    return;

                default:
                    Console.WriteLine("無効な入力です。");
                    break;
            }
        }
    }

    static void CreateAccount()
    {
        Console.Write("口座名義(例:田中太郎)を入力してください: ");
        string name = Console.ReadLine()!;
        if (accounts.ContainsKey(name))
        {
            Console.WriteLine("すでにこの名前の口座があります。");
            return;
        }

        var account = new BankAccount();
        account.Owner = name;
        accounts[name] = account;

        Console.WriteLine($"口座「{name}」を作成しました。");
    }

    static void Deposit()
    {
        Console.Write("入金する口座名義を入力してください: ");
        string name = Console.ReadLine()!;
        if (!accounts.TryGetValue(name, out var account))
        {
            Console.WriteLine("その口座は存在しません。");
            return;
        }

        Console.Write("入金金額を入力してください: ");
        if (int.TryParse(Console.ReadLine(), out int amount))
        {
            account.Deposit(amount);
            Console.WriteLine("入金しました。");
        }
        else
        {
            Console.WriteLine("数値を入力してください。");
        }
    }

    static void ShowBalance()
    {
        Console.Write("残高を確認する口座名義を入力してください: ");
        string name = Console.ReadLine()!;
        if (!accounts.TryGetValue(name, out var account))
        {
            Console.WriteLine("その口座は存在しません。");
            return;
        }

        Console.WriteLine($"口座「{name}」の残高は {account.GetBalance()} 円です。");
    }

    static void ShowAllAccounts()
    {
        if (accounts.Count == 0)
        {
            Console.WriteLine("まだ口座はありません。");
            return;
        }

        Console.WriteLine("登録されているすべての口座:");
        foreach (var kvp in accounts)
        {
            Console.WriteLine($"- {kvp.Key}: {kvp.Value.GetBalance()} 円");
        }
    }
}

🧠 8. チェックポイント!

質問□はい / □いいえ
クラスは設計図で、オブジェクトとは違うことがわかる
new しないとオブジェクトは存在しないと理解できた
Visual Studioの「開始」ボタンでコードが動くことを理解した
複数人の口座を Dictionary で管理する仕組みがわかった
質問□はい / □いいえ解説(なぜ「はい」か)
クラスは設計図で、オブジェクトとは違うことがわかる☑ はいクラスは「こういう機能を持つものを作るよ」という型(設計図)で、new して初めて実体(オブジェクト)ができる。
new しないとオブジェクトは存在しないと理解できた☑ はいnew BankAccount() を書かないと、taro や hanako のような具体的な口座は存在しない。
Visual Studioの「開始」ボタンでコードが動くことを理解した☑ はい書いただけのコードはまだ実行されていない。【開始】Start ボタンを押して Main() が始まって初めて動く。
複数人の口座を Dictionary で管理する仕組みがわかった☑ はいDictionary<string, BankAccount> を使えば、名前をキーにして複数の口座をひとまとめにして扱える。


🧪 9. チャレンジ課題(中級)

  • Withdraw() を追加して引き出し機能を実装しよう
  • 残高が足りなかったらエラーを出そう
  • 取引履歴を保存するために List<string> を追加しよう

以下に、チャレンジ課題(中級)の完全なサンプル解答を提示します。初心者にも理解しやすいように、段階ごとに解説付きで提示します。


🧪 9. チャレンジ課題(中級)サンプル解答

🎯 目的

  • Withdraw() メソッドの追加
  • 残高チェックの条件分岐
  • 取引履歴の記録(List<string>)

🧱 修正1:BankAccount.csクラスを拡張)

using System;
using System.Collections.Generic;

public class BankAccount
{
    public string Owner { get; set; } = "";
    private int balance;
    private List<string> history = new();

    public void Deposit(int amount)
    {
        balance += amount;
        history.Add($"入金: {amount}円(残高: {balance}円)");
    }

    public bool Withdraw(int amount)
    {
        if (balance >= amount)
        {
            balance -= amount;
            history.Add($"出金: {amount}円(残高: {balance}円)");
            return true;
        }
        else
        {
            history.Add($"出金失敗: {amount}円(残高不足)");
            return false;
        }
    }

    public int GetBalance()
    {
        return balance;
    }

    public List<string> GetHistory()
    {
        return new List<string>(history); // 外部からの変更を防ぐ
    }
}

🔁 修正2:Program.csに操作項目を追加

追加するメニュー

Console.WriteLine("[5] 口座の取引履歴を見る");

追加する case 分岐

case "5":
    ShowHistory();
    break;

🔧 修正3:

Withdraw()

 メニュー操作の実装

static void Withdraw()
{
    Console.Write("出金する口座名義を入力してください: ");
    string name = Console.ReadLine()!;
    if (!accounts.TryGetValue(name, out var account))
    {
        Console.WriteLine("その口座は存在しません。");
        return;
    }

    Console.Write("出金金額を入力してください: ");
    if (int.TryParse(Console.ReadLine(), out int amount))
    {
        if (account.Withdraw(amount))
        {
            Console.WriteLine("出金しました。");
        }
        else
        {
            Console.WriteLine("残高が不足しています。");
        }
    }
    else
    {
        Console.WriteLine("数値を入力してください。");
    }
}

📜 修正4:ShowHistory() の実装

static void ShowHistory()
{
    Console.Write("履歴を見る口座名義を入力してください: ");
    string name = Console.ReadLine()!;
    if (!accounts.TryGetValue(name, out var account))
    {
        Console.WriteLine("その口座は存在しません。");
        return;
    }

    var history = account.GetHistory();
    if (history.Count == 0)
    {
        Console.WriteLine("取引履歴はまだありません。");
    }
    else
    {
        Console.WriteLine("【取引履歴】");
        foreach (var record in history)
        {
            Console.WriteLine(record);
        }
    }
}

📌 補足

機能ポイント
Withdraw()成功・失敗を bool で返し、呼び出し側が結果に応じて出力制御できる
List<string>文字列形式で履歴を記録し、表示時にそのまま出力できる
GetHistory()外部から履歴が変更されないようコピーを返す

このサンプルは、拡張性のある設計になっており、さらに以下のような発展も可能です:

  • 日付付きの履歴(DateTime.Now)
  • CSVファイルに保存
  • 出金時の手数料追加 など

🎓 まとめ

  • クラス ≠ オブジェクト。設計図だけでは動かない。
  • Visual Studioの「Start」ボタンを押すまでオブジェクトは作られない。
  • new で実体(口座)が生まれ、メソッドを通じて操作できる。
  • 実行タイミング・ユーザー操作と連動する構造がOOPのポイント!

訪問数 3 回, 今日の訪問数 1回