【C#】インターフェイスの定義と実装によるクラス設計の基礎

C#などのオブジェクト指向プログラミングにおいて、「インターフェイス(Interface)」は非常に重要な役割を果たします。インターフェイスとは、クラスが実装すべき「機能の規格(契約)」を定義したものです。

インターフェイスを利用することで、具体的な処理内容(実装)と、利用するための窓口(定義)を切り離すことができ、柔軟で保守性の高いコードを記述できるようになります。今回は、メッセージ送信機能を題材に、インターフェイスの定義方法とクラスへの実装方法について解説します。


目次

インターフェイスの基本構文

インターフェイスの定義には interface キーワードを使用します。慣習として、名前の先頭には「I」を付けます(例: ISample)。

  • 定義できるもの: メソッド、プロパティ、イベント、インデクサの「シグネチャ(型や名前)」のみ。
  • 定義できないもの: 実際の処理内容(メソッドの中身)や、フィールド(変数)。
    • ※C# 8.0以降ではデフォルト実装が可能になりましたが、基本は「定義のみ」です。

実践的なコード例:メッセージ送信機能の規格化

以下のコードは、メッセージ送信機能を表す IMessageSender インターフェイスを定義し、それを具体的に実装した SmsSender クラスを作成する例です。

using System;

namespace MessagingSystem
{
    class Program
    {
        static void Main()
        {
            // インターフェイス型の変数としてインスタンスを扱うことが可能です。
            // これにより、具体的なクラス(SmsSender)の実装を知らなくても利用できます。
            IMessageSender sender = new SmsSender();

            sender.Send("090-1234-5678", "こんにちは。確認コードは 1234 です。");
            sender.Send("080-9876-5432", "予約が完了しました。");

            Console.WriteLine($"本日の送信合計数: {sender.SentCount} 件");
        }
    }

    // 1. インターフェイスの定義
    // クラスが「何をすべきか」という仕様だけを定義します。
    public interface IMessageSender
    {
        // メソッドの定義(アクセシビリティ修飾子は書きません)
        void Send(string recipient, string message);

        // プロパティの定義(getのみ、setのみ、両方などを指定可能)
        int SentCount { get; }
    }

    // 2. インターフェイスの実装
    // クラス名の後ろに「: インターフェイス名」を記述します。
    public class SmsSender : IMessageSender
    {
        // プロパティの実装
        // インターフェイスでは get のみが規定されていますが、
        // 実装側で private set を追加して内部で値を変更できるようにしています。
        public int SentCount { get; private set; }

        // メソッドの実装
        // インターフェイスで定義されたメソッドを必ず public で実装する必要があります。
        public void Send(string recipient, string message)
        {
            // 実際のSMS送信処理(ここではコンソール出力で代用)
            Console.WriteLine($"[SMS送信] To: {recipient}, Body: {message}");

            // 送信カウントをインクリメント
            SentCount++;
        }
    }
}

実行結果

[SMS送信] To: 090-1234-5678, Body: こんにちは。確認コードは 1234 です。
[SMS送信] To: 080-9876-5432, Body: 予約が完了しました。
本日の送信合計数: 2 件

技術的なポイント

1. 契約としての役割

インターフェイスを実装(class SmsSender : IMessageSender)すると、そのクラスはインターフェイスで定義された全てのメンバー(メソッドやプロパティ)を必ず実装しなければなりません。これを守らないとコンパイルエラーになります。これにより、「このインターフェイスを持っているクラスなら、必ずSendメソッドを呼べる」という保証が生まれます。

2. プロパティの実装とアクセシビリティ

インターフェイス側で { get; } と定義されていても、実装クラス側で { get; set; }{ get; private set; } として実装することは可能です。インターフェイスは「最低限これが必要」という要件を示すものだからです。 ただし、実装するメンバーは必ず public である必要があります。

3. ポリモーフィズム(多態性)の活用

上記の Main メソッドのように、変数の型をインターフェイス型(IMessageSender)にしておくことで、代入するインスタンスを SmsSender から EmailSenderLineSender に切り替えたとしても、呼び出し側のコード(Sendメソッドを呼ぶ部分)を変更せずに済みます。これがインターフェイスを利用する最大のメリットの一つです。

まとめ

インターフェイスを定義することで、アプリケーションの「仕様」と「実装」を分離できます。最初は手間に感じるかもしれませんが、テストの容易性や将来的な機能拡張(例えばSMS以外の送信手段の追加など)を考慮すると、クラス設計において必須のテクニックとなります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次