C#でのオブジェクト指向学習サンプル4(レジ、購入はバーコード番号入力だけにする)

2023年8月1日

バーコード入力で商品が購入できるようにしました

前回までのサンプル

ベースとなる基本レジ

シンプルで、これはこれでいいと思いますが、さらに現実のレジに近づけてみましょう

レジ、マイナスの商品は買えないようにする

C#のプロパティの機能を採用して、堅牢なコードに変更します
これは、オブジェクト指向の3大要素と呼ばれるカプセル化にあたります

レジ、購入商品数を最初に入力しなくてもよくする

Listクラスの機能を採用して、要素数が実行中に変更可能な配列のように変更します
これにより最初に買い物する商品数の入力が不要になりました

新たに実現したい機能

今のコードでは、顧客は最初に購入する商品名と値段を入力する必要がありますが、これは実際のスーパーの買い物で考えると少し不自然さを感じます

変更点としては、商品の情報(名前、値段)を入力するところで単にバーコードを入力することにします

購入はバーコード番号入力だけにするの実行結果

お客(山田さん)が買い物かごに買いたい商品を入れていきます
必要なものを入れたらレジで精算(レシート表示)します

最初に商品のバーコードを入力してもらっています
全ての買い物を終わったら単にエンターキーを押して買い物を終えたことにします

クラス図

イラスト

UML図

前回までの図からフラッシュアップしています

シーケンス図

コード

C#の初学であれば、次のポイントに注意して確認してください

クラスはブロック内を2つの部分に分けて分析してみます

属性(データ、フィールドともいいます)と振る舞い(動作の部分でメソッドや関数とも言います)の2つです

メソッドは、ブロック内を全て理解することを目的にせず、メソッド名から何の動作をさせようとしているのかを分析対象とします

PurchasedItem.cs(新しく追加されたクラス)

お客が購入する商品のクラスになります
これまでは、商品名や値段の属性を持ったものを使っていましたが(Itemクラス)、今回は、バーコードのみにしています
スーパーでの商品に貼ってあるラベルのイメージです
実際購入する場合、バーコードをスキャナで読ませればOKなので、そのような状況に合わせてみました

属性

バーコードのみ
コンストラクタで、バーコードが代入できるようにしています

振る舞い

ありません

class PurchasedItem
{
    public string barCode;

    public PurchasedItem(string barCode)
    {
        this.barCode = barCode;
    }
}

Item.cs

商品の一覧のクラスになります商品マスター(商品一覧)のデータの構造を定義しています
これまでは、お客の買い物かごに入っている商品を指していましたが、今回は商品の情報をまとめた一覧表(エクセルシートのようなもの)に変更しています
お客が保持していましたが、今回からはレジがこの情報を保持することになります


変更点は、バーコードの属性の追加になります

属性

バーコード商品名価格の3つで考えます

振る舞い

商品名と価格を表示するのみになります

// Itemクラス(設計図)
/// <summary>
/// スーパーの商品クラス
/// </summary>
class Item
{
    // (フィールド)
    // バーコード
    public string barCode;
    // 商品名
    public string name;

    // 価格
    // このクラス外からはアクセスできないフィールド(private修飾子)
    private int price;

    // (プロパティ)public修飾子なのでクラス外からアクセスできる
    public int Price
    {
        get
        {
            // 読み込まれた場合の処理
            return price;
        }
        set
        {
            // 書き込まれた場合の処理
            if (value < 0)
            {
                price = 0;
            }
            else
            {
                price = value;
            }
        }
    }

    // ------------------------------------

    // (メソッド、関数、プロシジャー、ファンクション)
    // 商品名と価格を表示する
    public void Show()
    {
        Console.WriteLine($"{name}の価格は{price}円です");
    }
}

Customer.cs

これまでは商品というものを持っているイメージでしたが、購入済み商品を持っていることに変更します

お客クラスになります
購入済み商品を複数持っていることを表しています

属性

お客様名複数の購入済み商品の2つで考えます

振る舞い

インスタンス作成時、名前を登録する購入するの2つになります

変更点は、次のようになります

class Customer
{
    public string name;

    // カートの商品
    public List<PurchasedItem> items;

    public Customer(string name)
    {
        this.name = name;
    }

    public void Buy()
    {
        // PurchasedItemクラス(購入済み商品)からインスタンスを作成する(オブジェクトを作成)
        // =>インスタンス化ともいいます

        items = new List<PurchasedItem>();

        while (true)
        {
            Console.Write("バーコード: ");
            string barCode = Console.ReadLine();

            if (barCode == "")
            {
                break;
            }

            items.Add(new PurchasedItem(barCode));
        }

    }

}

Reg.cs

レジクラスになります

属性

商品マスター(商品一覧)を持ちます

振る舞い

変更点は、次のようになります

レシートを表示するのみになります

class Reg
{
    // 商品マスター(商品一覧)
    List<Item> items = new List<Item>();

    public Reg()
    {
        // コンストラクタで商品マスターに商品を初期登録しています
        Item item1 = new Item { name = "りんご", barCode = "1234", Price = 100 };
        Item item2 = new Item { name = "ばなな", barCode = "2345", Price = 200 };

        items.Add(item1);
        items.Add(item2);
    }

    // レシートを表示する
    public void PrintReceipt(Customer customer)
    {
        //customer.items[0].Price = -100;
        Console.WriteLine($"{customer.name}さんのレシート");
        Console.WriteLine("----------------------------");

        // 合計金額を入れる変数を用意する
        int totalPrice = 0;

        // レシートの表示
        foreach (var item in customer.items)
        {
            // LINQを使って、お客が持っている購入済み商品のバーコードと商品マスター(一覧)のバーコードの一致を探し、
            // 結果をfindItem変数に代入しています
            var findItem = items.FirstOrDefault(itemMaster => item.barCode == itemMaster.barCode);

            // 商品名を表示する
            Console.WriteLine($"商品: {findItem.name} {findItem.Price}円");

            totalPrice += findItem.Price;
        }


        Console.WriteLine("----------------------------");

        // 合計を表示する
        Console.WriteLine($"合計金額は{totalPrice}円です");
    }

}

RegSystem.cs

メントで追加はしています)

レジのシステム全体をコントロールするクラスになります

属性

ありません

振る舞い

Runメソッドからコードが始まります

ここでは、お客様の山田さんの作成買い物をするレジの作成レシートを表示するを行なっています

class RegSystem
{
    public void Run()
    {

        // レジオブジェクトを作成
        Reg reg1 = new Reg();

        // 山田さんを作成
        Customer customer1 = new Customer("山田");
        customer1.Buy();
        reg1.PrintReceipt(customer1);

        /*
        Customer customer2 = new Customer("森本");
        Customer customer3 = new Customer("太田");

        // 森本さんが先に購入
        customer2.Buy();
        // 森本さんがそのまま清算
        reg1.PrintReceipt(customer2);
        customer3.Buy();

        reg1.PrintReceipt(customer3);
        */
    }
}

Program.cs

変更点はありません

C#でプログラムが実行される最初のメソッドになります

属性

ありません

振る舞い

ここでは、レジシステムの作成レジの実行を行なっています

RegSystem regSystem = new RegSystem();
regSystem.Run();

おまけ

PlantUML記法から図を作成するネットのサービス(無料)

シーケンス図

@startuml
!define REG_CLASS レジ
!define CUSTOMER_CLASS 顧客
!define ITEM_CLASS 商品
!define PURCHASEDITEM_CLASS 購入済み商品

actor 顧客

顧客 -> レジ: 購入()
loop
    顧客 -> レジ: バーコードを入力
    レジ --> 顧客: 購入済み商品を追加
end

顧客 --> レジ: レシートを表示()

レジ -> 商品: 商品を検索
loop
    レジ --> 顧客: レシートに商品を表示
    alt 商品が見つかった場合
        顧客 -> 商品: 商品名と価格を取得
        商品 --> 顧客: 商品名と価格を返す
        顧客 -> レジ: 合計金額を計算
        レジ --> 顧客: 合計金額を更新
    else 商品が見つからなかった場合
        顧客 --> レジ: エラー - 商品が見つかりませんでした
    end
end
顧客 --> レジ: 合計金額を表示
@enduml

クラス図

@startuml

class Program{
    -Main()
}

class Customer {
    +name: string
    +items: List<PurchasedItem>
    +Customer(name: string)
    +Buy()
}

class Item {
    +barCode: string
    +name: string
    -price: int
    +Price: int << get; set; >>
    +Show()
}

class PurchasedItem {
    +barCode: string
    +PurchasedItem(barCode: string)
}

class Reg {
    -items: List<Item>
    +Reg()
    +PrintReceipt(customer: Customer)
}

class RegSystem {
    +Run()
}

Customer --> PurchasedItem : has 1..* >
Reg --> Item : has 1..* >
Program --> RegSystem : creates >
RegSystem --> Customer : create >
RegSystem --> Reg : creates >
RegSystem --> Customer : uses >
RegSystem --> Reg : uses >

@enduml