C#でのオブジェクト指向学習サンプル3(レジ、購入商品数を最初に入力しなくてもよくする)

2023年8月1日

C#でのオブジェクト指向学習サンプル1(レジ基本)とC#でのオブジェクト指向学習サンプル2(C#でのオブジェクト指向学習サンプル2(レジ、マイナスの商品は買えないようにする)で、基本的なレジをシミュレートしてみました
まだ確認されていない方は、これから進めてください

前回までのサンプル

ベースとなる基本レジ

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

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

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

新たに実現したい機能

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

変更点としては、商品の数を入力するところで単にエンターキーを押すと購入が終わること(つまりそれまでは幾つでも買える)にします

レジ基本の実行結果

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

最初に購入商品数を入力してもらっています
これは、買い物かご(複数の商品)の管理を配列で行なっているためです

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

商品名でエンターキーを押すまで連続して商品を購入することができるようになりました

クラス図

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

コード

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

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

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

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

Item.cs

変更点はありません

商品クラスになります

属性

商品名価格の2つで考えます

振る舞い

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

// Itemクラス(設計図)
/// <summary>
/// スーパーの商品クラス
/// </summary>
class Item
{
    // (フィールド)
    // 商品名
    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

プロパティ化で、値段にアクセスする場合、price変数だったところをPrice変数に変更します

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

属性

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

振る舞い

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

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

class Customer
{
    public string name;

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

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

    public void Buy()
    {
        // Itemクラス(設計図)からインスタンスを作成する(オブジェクトを作成)
        // =>インスタンス化ともいいます

        items = new List<Item>();

        while (true)
        {
            Console.Write("商品名: ");
            string itemName = Console.ReadLine();

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

            Console.Write("価格: ");
            int itemPrice = int.Parse(Console.ReadLine());

            Item item = new Item { name = itemName, Price = itemPrice };

            items.Add(item);
        }

    }

}

Reg.cs

レジクラスになります

属性

ありません

レシートが記されていますが、表示用のため今回は考えなくていいでしょう

振る舞い

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

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

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

        // レシートの表示
        for (int i = 0; i < customer.items.Count; i++)
        {
            // 商品名を表示する
            Console.WriteLine($"商品{i + 1}: {customer.items[i].name} {customer.items[i].Price}円");
        }

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

        // 商品の数だけ繰り返す
        for (int i = 0; i < customer.items.Count; i++)
        {
            // 合計金額に商品の価格を足していく
            totalPrice += customer.items[i].Price;
        }

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

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

}

RegSystem.cs

変更点はありません

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

属性

ありません

振る舞い

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

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

class RegSystem 
{
    public void Run()
    {
        Customer customer1 = new Customer("山田");

        customer1.Buy();

        Reg reg1 = new Reg();

        reg1.PrintReceipt(customer1);
    }
}

Program.cs

変更点はありません

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

属性

ありません

振る舞い

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

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

おまけ

PlantUML記法

@startuml

class Program{
  -Main()
}
class RegSystem {
    + Run()
}

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

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


class Reg {
    + PrintReceipt(customer: Customer)
}

Program --> RegSystem : creates
RegSystem --> Customer : creates
RegSystem --> Reg : creates
Customer "1" --> "*" Item : has
RegSystem --> Reg : uses
RegSystem --> Customer : uses

@enduml

@startuml
actor Customer

Program -> RegSystem: new RegSystem()
Program -> RegSystem: Run()
RegSystem -> Customer: new Customer("山田")
Customer -> Customer: Buy()
Customer -> Console: "山田さんの買い物かごの商品の数は?"
Console -> Customer: itemCount
loop itemCount
    Customer -> Console: "商品名:"
    Console -> Customer: itemName
    Customer -> Console: "価格:"
    Console -> Customer: ItemPrice
    Customer -> Item: new Item(itemName, ItemPrice)
end
Customer -> Customer: items = Item[]
RegSystem -> Reg: new Reg()
Reg -> Reg: PrintReceipt(customer1)
Reg -> Console: "山田さんのレシート"
Reg -> Console: "----------------------------"
loop customer1.items.Length
    Reg -> Console: "商品i + 1: " + customer1.items[i].name + " " + customer1.items[I].Price + "円"
end
Reg -> Reg: totalPrice = 0
loop customer1.items.Length
    Reg -> Reg: totalPrice += customer1.items[i].Price
end
Reg -> Console: "----------------------------"
Reg -> Console: "合計金額は" + totalPrice + "円です"
@enduml

@startuml
skinparam shadowing false

start

:顧客インスタンスを作成;
:買い物かごの商品数を入力;
while (商品数 > 0)
    :商品名を入力;
    :価格を入力;
endwhile

:レジシステムを実行;

:レシートを表示;

stop

@enduml