staticクラスとstaticメソッドを料理で理解する:newしないで呼び出す共通の道具箱

広告

C#を学び始めると、staticという言葉が何度も登場します。staticメンバーは、特定のインスタンスではなく、クラスそのものに所属する機能です。最初は「インスタンスを作らずに使える共通の道具箱」と考えると理解しやすくなります。

この記事では、「料理」と「レシピ」を題材にして、static修飾子・staticクラス・staticメソッドの基本を見ていきます。

staticとは「クラスそのものに所属する機能」

通常のクラスでは、newを使ってインスタンスを作り、インスタンスごとに異なるデータを持たせられます。一方、staticメンバーは特定のインスタンスに所属しないため、インスタンスを作らなくてもクラス名から使えます。

たとえば焼きそばの作り方は、「Aさん専用の手順」「Bさん専用の手順」のように、作る人ごとに別の状態を持つ必要がありません。決まったレシピを共通の道具箱に入れておき、必要なときに呼び出せば十分です。このため、「料理・レシピ」はインスタンスの状態を持たないstaticメソッドの説明に向いています。

複数の人が同じ料理道具箱を共有して使うイラスト
staticメンバーは、特定のインスタンスを作らずに使える「共通の道具箱」のイメージです。

完成したサンプルコード

using System;

namespace StaticClassTutorial
{
    static class 料理レシピ
    {
        public static void 焼きそばを作る()
        {
            Console.WriteLine("材料を用意する");
            Console.WriteLine("野菜を炒める");
            Console.WriteLine("麺を加えて炒める");
            Console.WriteLine("ソースで味付けする");
            Console.WriteLine("皿に盛り付ける");
        }

        public static string お好み焼きを作る(int 枚数)
        {
            int 小麦粉の量 = 100 * 枚数;

            Console.WriteLine($"小麦粉を{小麦粉の量}g計量する");
            Console.WriteLine("生地の材料を混ぜる");
            Console.WriteLine($"{枚数}枚分の生地を焼く");
            Console.WriteLine("ソースをかけて盛り付ける");

            return $"{枚数}枚のお好み焼きができました";
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            // staticクラスはnewできません
            // コメントを外すとコンパイルエラーになります
            // 料理レシピ 特別なレシピ = new 料理レシピ();

            料理レシピ.焼きそばを作る();

            string 結果 = 料理レシピ.お好み焼きを作る(3);
            Console.WriteLine(結果);
        }
    }
}

注釈:このサンプルでは、初学者が処理の意味を直感的に理解できるよう、日本語のクラス名・メソッド名・変数名を使用しています。C#では日本語を含むUnicode文字を識別子に使用できますが、チーム開発や公開ライブラリでは、既存の命名規則に合わせて英語で命名するのが一般的です。

英語で命名する場合は、クラス名をCookingRecipes、メソッド名をMakeYakisobaMakeOkonomiyaki、枚数を表す引数をnumberOfPiecesなどにすると、役割が伝わりやすくなります。C#の一般的な規則では、クラス名とメソッド名はPascalCase、引数とローカル変数はcamelCaseにします。

今回は、料理レシピクラスとProgramクラスが同じ小さなサンプルを構成するため、同じStaticClassTutorial namespaceに置いています。通常、namespaceはクラスごとに分けるのではなく、関連する型を用途や機能のまとまりで整理するために使います。

staticクラスはnewできない

static class 料理レシピと宣言したクラスは、インスタンスを作れません。そのため、次のコードはコメントアウトしています。

// 料理レシピ 特別なレシピ = new 料理レシピ();

コメントを外すとコンパイルエラーになります。この行をあえて残すことで、「staticクラスはnewできない」という特徴を実際に試せる教材になります。エラーを見ることも、仕組みを理解する大切な実験です。

クラス名.メソッド名で直接呼び出す

staticメソッドは、インスタンスを作らずに「クラス名.メソッド名」で呼び出します。なお、staticメソッドはstaticクラスにだけ定義できるものではなく、通常の非staticクラスにも定義できます。今回は特徴を分かりやすくするため、staticクラスにまとめています。

料理レシピ.焼きそばを作る();

ここでは、料理レシピがクラス名、焼きそばを作るがメソッド名です。new 料理レシピ()を先に書いていない点に注目してください。クラスそのものに所属する機能を、クラス名から直接呼び出しています。

2つのメソッドで引数と戻り値を比べる

枚数を入力し、お好み焼きを作って結果を返す流れのイラスト
引数として枚数を受け取り、調理処理を行い、完成結果を戻り値として返す流れです。

焼きそばを作る()は、引数なし・戻り値なしのメソッドです。呼び出すだけで、決められた手順を順番に表示します。戻り値がないため、戻り値の型にはvoidを指定しています。

public static void 焼きそばを作る()

一方、お好み焼きを作る(int 枚数)は、引数あり・戻り値ありのメソッドです。枚数を受け取り、必要な小麦粉を100 * 枚数で計算し、小麦粉の量という変数に保存します。最後に完成した枚数を含む文字列を返すため、戻り値の型はstringです。

string 結果 = 料理レシピ.お好み焼きを作る(3);
Console.WriteLine(結果);

結果変数で戻り値を受け取り、Console.WriteLine(結果);で表示するところまで書くことで、「返された値を受け取って使う」という流れが完結します。実行すると、料理の手順に続いて「3枚のお好み焼きができました」と表示されます。

staticが向かない場合もある

共通の料理レシピと個別の生徒データを比較するイラスト
個別の状態を必要としない処理ではstaticが候補になり、名前や点数など個別の状態を持つものにはインスタンスが向いています。

すべてをstaticにすればよいわけではありません。たとえばStudentクラスで、生徒ごとに名前や点数を持たせたい場合を考えてみましょう。

Student 田中さん = new Student("田中", 80);
Student 佐藤さん = new Student("佐藤", 95);

田中さんと佐藤さんでは、名前も点数も異なります。このように個別の状態を持つものは、newして別々のインスタンスを作る方が自然です。

  • 特定のインスタンスの状態を使わず、入力から結果を計算するなど責任が明確な処理:staticが候補
  • 人や商品など、1つずつ異なる状態を持つ:インスタンスが候補

ただし、「共通で使うから」という理由だけで何でもstaticにするのは避けましょう。雑多な処理を1つのstaticクラスへ集めると、責任が分かりにくくなります。また、あとから実装を差し替えたい処理や、テストで別の動作に置き換えたい処理では、インターフェイスとインスタンスを使う設計が適することもあります。

まとめ

staticメンバーは、特定のインスタンスではなくクラスそのものに所属する機能です。staticクラスはnewできず、staticメソッドは料理レシピ.焼きそばを作る();のように「クラス名.メソッド名」で直接呼び出します。

特定のインスタンスの状態を必要とせず、責任が明確な処理ではstaticが候補になります。一方、名前や点数など個別の状態を持つStudentのようなものは、インスタンスを作る方が自然です。「共通かどうか」だけでなく、「個別の状態を扱うか」「処理の責任が明確か」「実装を差し替える必要があるか」も意識すると、staticを使う場面を判断しやすくなります。

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

広告

.NET,C#

Posted by hidepon