基礎から学ぶC#入門 90日コース | クラス・インスタンス・設計 - Day 39:複数クラスの連携

Web APP 90日で身につけるC#
スポンサーリンク
スポンサーリンク

Day 39 のゴールと全体像

Day 39 のテーマは 「複数クラスの連携」 です。 ここまでで、1つのクラスの中に「データ」と「処理」をまとめる感覚はだいぶ育ってきたと思います。

今日はそこから一歩進んで、

  • Program
  • Service
  • Model

という 3 つの役割に分けて、 クラス同士を連携させる「小さな設計」を体験していきます。

ざっくり言うと、

Program:アプリの入口・流れを決める Service:具体的な仕事を担当する Model:データの形を表す

という役割分担を、 シンプルな例で感じてもらう回です。

3つの役割をざっくりイメージする

Model:データの「型」を表すクラス

まずは Model からいきます。

Model は、

「アプリの中で扱うデータの形を表すクラス」

です。

たとえば、前回の Product クラスは、 まさに「商品というデータのモデル」でした。

シンプルな例として、 ユーザー情報を表す User モデルを作ってみます。

// Model:データの形を表すクラス
class User
{
    // ユーザーID
    public int Id { get; }

    // 名前
    public string Name { get; }

    // メールアドレス
    public string Email { get; }

    public User(int id, string name, string email)
    {
        Id = id;
        Name = name;
        Email = email;
    }

    // 自分の情報を表示するメソッド(Model によくある補助的な処理)
    public void PrintInfo()
    {
        Console.WriteLine($"ID: {Id}, 名前: {Name}, メール: {Email}");
    }
}
C#

ここでは、

  • User は「ユーザーというデータの形」を表している
  • データの整合性(ID・名前・メール)をコンストラクタで保証している

という役割を持っています。

Service:具体的な仕事を担当するクラス

次に Service です。

Service は、

「アプリの中で行いたい具体的な処理を担当するクラス」

です。

例えば、

  • ユーザーを登録する
  • ユーザー一覧を表示する
  • ユーザーを検索する

といった「仕事」をまとめて持つクラスが、Service になります。

先ほどの User モデルを使って、 UserService を作ってみます。

using System;
using System.Collections.Generic;
using System.Linq;

// Service:ユーザーに関する処理を担当するクラス
class UserService
{
    // ユーザー一覧(簡易的にメモリ上の List で管理)
    private readonly List<User> users = new List<User>();

    // ユーザーを追加する
    public void AddUser(User user)
    {
        users.Add(user);
        Console.WriteLine($"ユーザー「{user.Name}」を追加しました。");
    }

    // 全ユーザーを表示する
    public void PrintAllUsers()
    {
        Console.WriteLine("ユーザー一覧:");
        foreach (var user in users)
        {
            user.PrintInfo();
        }
    }

    // ID でユーザーを検索する
    public User? FindById(int id)
    {
        return users.FirstOrDefault(u => u.Id == id);
    }
}
C#

ここでは、

  • UserService は「ユーザーに関する仕事」を担当している
  • データの実体(User)は Model に任せている
  • 複数の User をまとめて扱う処理を持っている

という構造になっています。

Program:アプリの入口と全体の流れ

最後に Program です。

Program クラス(Main メソッドがあるところ)は、

「アプリの入口であり、全体の流れを組み立てる場所」

です。

ここでは、

  • どの Service を使うか
  • どの Model を作るか
  • どんな順番で処理を呼び出すか

といった「シナリオ」を書いていきます。

先ほどの UserUserService を使って、 Program を書いてみます。

class Program
{
    static void Main(string[] args)
    {
        // Service を用意する
        UserService userService = new UserService();

        // Model を作って Service に渡す
        User user1 = new User(1, "太郎", "taro@example.com");
        User user2 = new User(2, "花子", "hanako@example.com");

        userService.AddUser(user1);
        userService.AddUser(user2);

        // 一覧表示
        userService.PrintAllUsers();

        // 検索してみる
        User? found = userService.FindById(2);
        if (found != null)
        {
            Console.WriteLine("ID 2 のユーザーが見つかりました:");
            found.PrintInfo();
        }
        else
        {
            Console.WriteLine("ID 2 のユーザーは見つかりませんでした。");
        }

        Console.ReadLine();
    }
}
C#

ここでは、

  • Program は「アプリの流れ」を書いている
  • UserService に「ユーザーを追加して」「一覧を表示して」「検索して」とお願いしている
  • User は「ユーザーというデータの形」として使われている

という役割分担になっています。

Program → Service → Model の流れを整理する

矢印の意味を具体的にイメージする

Day 39 のキーワードは、

Program ↓ Service ↓ Model

でした。

先ほどの例を、この矢印に当てはめてみると、

  • Program
    • Main メソッドでアプリの流れを決める
    • UserService を作って使う
    • User を作って UserService に渡す
  • Service
    • UserService が「ユーザーに関する処理」を担当する
    • User(Model)を使って仕事をする
  • Model
    • User が「ユーザーというデータの形」を表す

という関係になっています。

矢印の向きは、

  • Program が Service を使う
  • Service が Model を使う

という「上から下への依存関係」を表しています。

重要ポイント:

  • Program は「全体の流れ」を書く場所
  • Service は「具体的な仕事」をまとめる場所
  • Model は「データの形」を表す場所

という役割分担を意識すると、 コードの見通しがぐっと良くなります。

なぜ役割を分けると楽になるのか

1つのクラスに全部詰め込むとどうなるか

もし、Program の中に、

  • ユーザーのデータ
  • ユーザー一覧の管理
  • 検索処理
  • 表示処理

を全部書いてしまうと、 Main メソッドがどんどん長くなり、

「どこで何をしているのか分からない巨大メソッド」

になりがちです。

役割を分けることで、

  • データのことは Model に聞けばいい
  • ユーザーに関する処理は UserService を見ればいい
  • アプリ全体の流れは Program を見ればいい

というふうに、 「見るべき場所」がはっきりします。

修正や拡張がしやすくなる

例えば、

  • ユーザーの保存先を「メモリ上の List」から「ファイル」や「データベース」に変えたい
  • ユーザーの項目を増やしたい(住所や電話番号など)
  • ユーザー一覧の表示方法を変えたい

といった変更が入ったとき、

  • 保存方法の変更 → Service を中心に直す
  • 項目の追加 → Model を中心に直す
  • 表示方法の変更 → Service や Program を中心に直す

というふうに、 「どこを直せばいいか」が分かりやすくなります。

重要ポイント:

  • 役割分担は「後から直しやすくするための工夫」でもあります。
  • 小さなプログラムでも、早めにこの感覚を持っておくと、 大きなプログラムに進んだときに楽になります。

Day 39 用の練習テンプレート

最後に、Program → Service → Model の流れを練習するための、 シンプルなテンプレートを紹介します。

商品管理のミニ例

using System;
using System.Collections.Generic;

// Model:商品データの形
class Product
{
    public int Id { get; }
    public string Name { get; }
    public int Price { get; }
    public int Stock { get; private set; }

    public Product(int id, string name, int price, int stock)
    {
        Id = id;
        Name = name;
        Price = price;
        Stock = stock;
    }

    public void PrintInfo()
    {
        Console.WriteLine($"ID: {Id}, 名前: {Name}, 価格: {Price} 円, 在庫: {Stock}");
    }

    public void AddStock(int amount)
    {
        Stock += amount;
    }

    public void ReduceStock(int amount)
    {
        if (amount > Stock)
        {
            Console.WriteLine("在庫不足です。");
            return;
        }
        Stock -= amount;
    }
}

// Service:商品に関する処理を担当
class ProductService
{
    private readonly List<Product> products = new List<Product>();

    public void AddProduct(Product product)
    {
        products.Add(product);
        Console.WriteLine($"商品「{product.Name}」を追加しました。");
    }

    public void PrintAllProducts()
    {
        Console.WriteLine("商品一覧:");
        foreach (var p in products)
        {
            p.PrintInfo();
        }
    }

    public Product? FindById(int id)
    {
        foreach (var p in products)
        {
            if (p.Id == id)
            {
                return p;
            }
        }
        return null;
    }
}

// Program:アプリの入口と流れ
class Program
{
    static void Main(string[] args)
    {
        ProductService productService = new ProductService();

        // Model を作って Service に渡す
        Product notebook = new Product(1, "ノート", 100, 50);
        Product pen = new Product(2, "ボールペン", 150, 30);

        productService.AddProduct(notebook);
        productService.AddProduct(pen);

        productService.PrintAllProducts();

        // ID 2 の商品を探して在庫を減らす
        Product? found = productService.FindById(2);
        if (found != null)
        {
            Console.WriteLine("ID 2 の商品が見つかりました。1 個販売します。");
            found.ReduceStock(1);
            found.PrintInfo();
        }

        Console.ReadLine();
    }
}
C#

このテンプレートを眺めながら、

  • Model(Product)は「商品というデータの形」を表している
  • Service(ProductService)は「商品一覧の管理や検索」を担当している
  • Program は「どの商品を作って、どう扱うか」という流れを書いている

という役割分担を意識してみると、 複数クラスの連携のイメージがぐっとクリアになります。

Day 39 のまとめ

Day 39 では、

  • Model:データの形を表すクラス
  • Service:具体的な仕事を担当するクラス
  • Program:アプリの入口と全体の流れを組み立てるクラス

という 3 つの役割を通して、

Program ↓ Service ↓ Model

という「小さな設計の階層」を体験しました。

この考え方は、

  • Webアプリ
  • デスクトップアプリ
  • モバイルアプリ

など、どんな種類のアプリでもよく使われる基本パターンです。

ぜひ、

  • 自分で小さなテーマ(タスク管理、メモ帳、図書管理など)を決めて
  • Model・Service・Program に分けてクラスを作ってみる
  • 「この処理はどのクラスの責務か?」を考えながらコードを書く

という練習を通して、 複数クラスの連携を 「難しい設計」ではなく、 役割分担を考える楽しい作業として、少しずつ体に馴染ませていってください。

タイトルとURLをコピーしました