C# Academy · レッスン

静的設計とインスタンス設計

静的な状態が適切な場面を判断します。

レッスン 4/413 ステップ

「静的設計とインスタンス設計」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。

設計上の選択

static と instance のどちらを選ぶかは、設計上の判断です。重要なのは、その動作がオブジェクトごとの状態に依存するのか、それとも入力だけに依存するのかという点です。

using System;

class Program
{
    // Depends only on inputs -> good static method
    static int Max(int a, int b) => a > b ? a : b;

    static void Main()
    {
        Console.WriteLine(Max(3, 8));
    }
}

状態を持たないロジックには static を使う

メソッドがインスタンスフィールドを必要とせず、入力を変換するだけなら static にします。数学用のヘルパーやフォーマッターが代表的な例です。

using System;

static class Convert2
{
    public static double MilesToKm(double miles) => miles * 1.60934;
}

class Program
{
    static void Main()
    {
        Console.WriteLine(Convert2.MilesToKm(10).ToString("0.0") + " km");
    }
}

状態には instance を使う

動作がオブジェクトごとに異なるデータに依存する場合は、instance を使用します。それぞれのオブジェクトが独自の状態を保持します。

using System;

class Counter
{
    private int _count;
    public void Increment() => _count++;
    public int Value => _count;
}

class Program
{
    static void Main()
    {
        var a = new Counter();
        var b = new Counter();
        a.Increment();
        a.Increment();
        b.Increment();
        Console.WriteLine("a=" + a.Value + ", b=" + b.Value);
    }
}

共有状態はグローバル状態

static フィールドは実質的にグローバルです。プログラムの多くの部分から読み書きされると、見つけにくいバグの原因になることがあります。ユーザーごとに独自のコピーが必要な場合は、インスタンス状態を優先しましょう。

using System;

class BadCart
{
    public static int Items;   // shared by EVERYONE -> usually wrong for a cart
}

class Program
{
    static void Main()
    {
        BadCart.Items++;
        BadCart.Items++;
        Console.WriteLine("All carts share: " + BadCart.Items);
    }
}

テスト容易性

純粋な static メソッドは、同じ入力に対して同じ出力を返すため、テストが簡単です。一方、変更可能な static 状態はテスト間に影響を漏らし、テストを壊れやすくします。

using System;

static class Calc
{
    public static int Add(int a, int b) => a + b;   // trivially testable
}

class Program
{
    static void Main()
    {
        Console.WriteLine(Calc.Add(2, 2) == 4 ? "pass" : "fail");
    }
}

ファクトリーヘルパーには static を使う

static ファクトリーメソッドは、設定済みのインスタンスを説明的な名前で作成できる、すっきりした方法です。

using System;

class Color
{
    public int R, G, B;
    private Color(int r, int g, int b) { R = r; G = g; B = b; }

    public static Color Red() => new Color(255, 0, 0);
    public static Color White() => new Color(255, 255, 255);
}

class Program
{
    static void Main()
    {
        var c = Color.Red();
        Console.WriteLine(c.R + "," + c.G + "," + c.B);
    }
}

new を避けるためだけに static にしない

オブジェクトの作成を避けるために、すべてを static にしてはいけません。型が状態を持つものを表す場合は、インスタンスを使うことで、その状態を分離して安全に管理できます。

using System;

class Player
{
    public string Name;
    public int Health = 100;
    public void TakeDamage(int d) => Health -= d;
}

class Program
{
    static void Main()
    {
        var p1 = new Player { Name = "A" };
        var p2 = new Player { Name = "B" };
        p1.TakeDamage(30);
        Console.WriteLine(p1.Name + ": " + p1.Health + ", " + p2.Name + ": " + p2.Health);
    }
}

両方を適切に組み合わせる

多くのクラスでは、共有する定数やカウンターに static メンバーを使い、オブジェクトごとのデータにインスタンスメンバーを使います。この組み合わせは、ごく自然な書き方です。

using System;

class Invoice
{
    private static int _seq = 1000;
    public readonly int Number;
    public decimal Amount;

    public Invoice(decimal amount)
    {
        Number = _seq++;
        Amount = amount;
    }
}

class Program
{
    static void Main()
    {
        var i1 = new Invoice(50m);
        var i2 = new Invoice(75m);
        Console.WriteLine(i1.Number + " / " + i2.Number);
    }
}

並行性に関する注意

共有された static 状態には複数のスレッドが同時にアクセスできるため、競合状態が発生する危険があります。1つのスレッドに限定されたインスタンス状態は、デフォルトでより安全です。

using System;

class SafeCalc
{
    // No shared mutable state -> naturally thread-safe
    public static long Factorial(int n)
    {
        long result = 1;
        for (int i = 2; i <= n; i++) result *= i;
        return result;
    }
}

class Program
{
    static void Main()
    {
        Console.WriteLine(SafeCalc.Factorial(5));
    }
}

簡単な判断基準

Static = 型に属し、オブジェクトごとの状態を使わない動作です。Instance = 特定のオブジェクトを読み取る、または変更する動作です。迷った場合は、状態を持つものには instance を優先しましょう。

using System;

class Temperature
{
    public double Celsius;                                  // instance state
    public static double ToF(double c) => c * 9 / 5 + 32;   // stateless helper
}

class Program
{
    static void Main()
    {
        var t = new Temperature { Celsius = 30 };
        Console.WriteLine(Temperature.ToF(t.Celsius));
    }
}

まとめ

優れた設計では、状態を持たないヘルパー(static)と状態を持つモデル(instance)を分離し、共有される変更可能な状態を意図的に最小限に抑えます。

using System;

static class TaxRules
{
    public static decimal Apply(decimal amount, decimal rate) => amount + amount * rate;
}

class Sale
{
    public decimal Subtotal;
    public decimal Total(decimal rate) => TaxRules.Apply(Subtotal, rate);
}

class Program
{
    static void Main()
    {
        var s = new Sale { Subtotal = 100m };
        Console.WriteLine(s.Total(0.2m));
    }
}

理解度チェック

static と instance の設計について理解できているか確認しましょう。

まとめ

入力だけに依存する状態を持たないロジック(ヘルパー、ファクトリー、定数)には static を、オブジェクトごとの状態に結び付いた動作には instance を選びます。変更可能な static 状態は実質的にグローバルで、テストが難しく、並行性に関するバグの原因にもなるため、最小限にとどめ、意図を明確にしましょう。

using System;

static class Util { public static int Sq(int n) => n * n; }

class Box { public int Size; public int Area() => Util.Sq(Size); }

class Program
{
    static void Main()
    {
        var box = new Box { Size = 4 };
        Console.WriteLine(box.Area());
    }
}
無料で開始

AI チューターと学ぶ C# — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
93
レッスン
346

よくある質問

「静的設計とインスタンス設計」レッスンは無料ですか?

はい。「静的設計とインスタンス設計」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。

「静的設計とインスタンス設計」で何を学びますか?

静的な状態が適切な場面を判断します。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C# Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「静的設計とインスタンス設計」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC# Academyレッスンでコードを書いて実行できますか?

はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 静的メソッドとフィールド
  2. ユーティリティ用の静的クラス
  3. 定数とreadonlyフィールド
  4. 静的設計とインスタンス設計
← C# Academyに戻る