セルフレジで体験する「はじめてのクラス」チュートリアル
変数・条件分岐・ループ・配列まで学んだ人向け
目次
0. ゴール
- クラスとは何かを体験して理解する
- カプセル化(データの隠蔽)の基本を感じ取る
- 既習内容(配列・if 文・for ループ)だけでミニアプリを完成させる
この章では行わないこと
コンストラクタ/継承/ポリモーフィズム/List/例外処理
1. 準備
- Visual Studio または VS Code で C# コンソールアプリを新規作成
- ソリューション名は、SelfCheckoutTutorialとしておきましょう
2. Step-by-Step 実装
Step 1 : 商品を表す Item クラスを作る
// Item.cs
class Item
{
public string Code; // 商品コード
public string Name; // 商品名
public int Price; // 価格(円)
}
ポイント
- “ひとまとめの箱” がクラス
- 今回はフィールド(変数)だけを持つシンプル構成
Step 2 : レジ本体 SelfCheckout クラスを作る
// SelfCheckout.cs
using System;
class SelfCheckout
{
private Item[] items = new Item[10]; // 買い物かご(10 点まで)
private int index = 0; // 今何点入っているか
// スキャンしてカゴに入れる
public void Scan(Item item)
{
items[index++] = item;
Console.WriteLine($"{item.Name} を登録({item.Price}円)");
}
// 合計金額を計算
public int CalcTotal()
{
int sum = 0;
for (int i = 0; i < index; i++)
{
sum += items[i].Price;
}
return sum;
}
// レシート印字
public void PrintReceipt()
{
Console.WriteLine("\n--- レシート ---");
for (int i = 0; i < index; i++)
{
Console.WriteLine($"{items[i].Name,-10} {items[i].Price,6}円");
}
Console.WriteLine($"合計 {CalcTotal(),6}円");
Console.WriteLine("------------\n");
}
}
ポイント
- items と index は private → 外から直接触れない
- 外部はメソッド (Scan, CalcTotal, PrintReceipt) だけを呼べる
Step 3 : エントリポイント Program を書く
// Program.cs
using System;
class Program
{
static void Main()
{
// 商品マスタ(object 初期化子で値を詰める)
Item apple = new Item { Code="A01", Name="りんご", Price=120 };
Item bread = new Item { Code="B01", Name="パン", Price=150 };
Item milk = new Item { Code="C01", Name="牛乳", Price=180 };
var reg = new SelfCheckout();
// りんご→パン→牛乳 をスキャン
reg.Scan(apple);
reg.Scan(bread);
reg.Scan(milk);
reg.PrintReceipt();
// 支払(if 文だけで分岐)
int total = reg.CalcTotal();
Console.Write("支払方法 (1:現金 2:カード)> ");
string sel = Console.ReadLine()!;
if (sel == "1")
{
Console.Write("投入金額> ");
int cash = int.Parse(Console.ReadLine()!);
Console.WriteLine($"お預り: {cash}円 おつり: {cash - total}円");
}
else
{
Console.WriteLine($"カード決済 {total}円 承認OK");
}
Console.WriteLine("ご利用ありがとうございました");
}
}
3. 動かしてみよう
- ビルドして実行
- コンソールに商品登録→レシート→支払選択が表示されれば成功
4. 学習チェック
チェック項目 | 自分の理解 |
---|---|
Item と SelfCheckout が別クラスである理由を説明できる | □はい / □いいえ |
private Item[] items を public にしたら何が起きるか想像できる | □はい / □いいえ |
Scan() を 11 回呼ぶとどうなるか確認し、原因を説明できる | □はい / □いいえ |
学習チェック ― サンプル解答
チェック項目 | 模範的な説明例 |
---|---|
Item と SelfCheckout が別クラスである理由 | 責務分離 のため。 – Item は「商品」という“データの塊”を表し、価格や名前などの商品情報だけを持つ。 – SelfCheckout は「レジ」という“振る舞いの塊”を担当し、商品のスキャンや合計計算などの処理を行う。役割を分けることでコードが読みやすくなり、片方を変更してももう片方へ影響しにくくなる。 |
private Item[] items を public にした場合に起きること | 外部コードが items 配列へ直接アクセスできるようになり、以下の問題が起きやすい。 1. 不正操作: 配列要素を勝手に上書き/削除され合計金額が狂う。 2. 整合性破壊: index フィールドと配列の中身がズレ、CalcTotal() が正しい合計を出せなくなる。 3. バグ発見が困難: 不具合の原因がレジ内部か呼び出し側か区別しづらくなる。→ カプセル化の破壊。 |
Scan() を 11 回呼ぶとどうなるか、その原因 | 配列 items の長さは 10 なので、11 回目で items[10] に代入しようとして IndexOutOfRangeException が発生し、プログラムが落ちる(例外未処理の場合)。原因は「固定長配列の上限を超えた」ため。index が 10 以上にならないようにチェックを入れるか、動的サイズの List<Item> に変更する必要がある。 |
5. 練習課題
- 商品を 5 点以上 用意してスキャンし、レシートを確認せよ
- SelfCheckout.CalcTotal() を 拡張税率 8% → 10% に切り替えられるよう改造せよ
- SelfCheckout に Clear() メソッド(配列を空に戻す)を追加して動作を確かめよ
以下は 練習課題 ①〜③ をすべて満たすサンプル実装です。
変更点の要所 → ★ コメントでマーキングしています。
using System;
namespace SelfCheckoutStep2
{
// 1. 商品クラス(変更なし)
class Item
{
public string Code;
public string Name;
public int Price; // 税抜き価格
}
// 2. レジ本体クラス
class SelfCheckout
{
private Item[] items = new Item[20]; // ★ 最大 20 点に拡大
private int index = 0;
public int TaxPercent { get; set; } = 10; // ★ 税率プロパティ(デフォルト 10%)
// 商品を登録
public void Scan(Item item)
{
items[index++] = item;
Console.WriteLine($"{item.Name} を登録({item.Price}円)");
}
// ★ 合計(税込み)を計算
public int CalcTotal()
{
int sum = 0;
for (int i = 0; i < index; i++)
{
sum += items[i].Price;
}
double rate = 1 + TaxPercent / 100.0; // 1.08 または 1.10
return (int)Math.Round(sum * rate, MidpointRounding.AwayFromZero);
}
// レシート印字
public void PrintReceipt()
{
Console.WriteLine("\n--- レシート ---");
for (int i = 0; i < index; i++)
{
Console.WriteLine($"{items[i].Name,-12} {items[i].Price,6}円");
}
Console.WriteLine($"税率 {TaxPercent,2}%");
Console.WriteLine($"合計 {CalcTotal(),6}円");
Console.WriteLine("------------\n");
}
// ★ カゴを空にする
public void Clear()
{
index = 0; // 先頭に戻すだけで OK
Console.WriteLine("カゴを空にしました\n");
}
}
// 3. 動作確認用プログラム
class Program
{
static void Main()
{
// ① 商品を 5 点以上用意
Item[] master =
{
new Item { Code="A01", Name="りんご", Price=120 },
new Item { Code="B01", Name="パン", Price=150 },
new Item { Code="C01", Name="牛乳", Price=180 },
new Item { Code="D01", Name="ミネラル水", Price=100 },
new Item { Code="E01", Name="チョコ", Price=220 }
};
var reg = new SelfCheckout();
// --- ② 税率 8% でスキャン ---
reg.TaxPercent = 8; // ★ 軽減税率に切り替え
foreach (var item in master) // 5 点すべて登録
{
reg.Scan(item);
}
reg.PrintReceipt(); // レシート確認
// --- ③ Clear() を呼び、税率 10% で再計算 ---
reg.Clear(); // ★ カゴの中身を空に
reg.TaxPercent = 10; // ★ 標準税率に戻す
// 同じ商品をもう一度スキャン(今度は 10%)
foreach (var item in master)
{
reg.Scan(item);
}
reg.PrintReceipt();
}
}
}
実行結果イメージ
りんご を登録(120円)
パン を登録(150円)
牛乳 を登録(180円)
ミネラル水 を登録(100円)
チョコ を登録(220円)
--- レシート ---
りんご 120円
パン 150円
牛乳 180円
ミネラル水 100円
チョコ 220円
税率 8%
合計 831円
------------
カゴを空にしました
りんご を登録(120円)
パン を登録(150円)
牛乳 を登録(180円)
ミネラル水 を登録(100円)
チョコ を登録(220円)
--- レシート ---
りんご 120円
パン 150円
牛乳 180円
ミネラル水 100円
チョコ 220円
税率 10%
合計 924円
------------
学習ポイントまとめ
課題 | 反映されたコード | 重要キーワード |
---|---|---|
① 5 点以上スキャン | foreach (var item in master) | 配列ループ |
② 税率切替 | TaxPercent プロパティ & 計算式 rate = 1 + TaxPercent / 100.0 | プロパティ、四則演算 |
③ Clear() | index = 0; で配列の先頭に戻すだけ | 状態リセット、カプセル化 |
このサンプルを写経 → 変更 → 実行しながら、「クラスの中で状態を管理し、それを操作するメソッドを追加する」感覚をつかんでください。
6. まとめと次の一歩
- クラスは「データ(フィールド)+手続き(メソッド)」をまとめる道具
- private でデータを隠し、メソッド経由で扱うのが カプセル化 の第一歩
- 次回は コンストラクタ を使って安全に初期化する方法を学ぶ
これで 「クラスを使う」ことそのもの に慣れました。
自分のコードに “役割ごとに箱を作る” 視点を取り入れてみましょう。
訪問数 23 回, 今日の訪問数 1回
ディスカッション
コメント一覧
まだ、コメントがありません