uniface.hub

ユニフェイスの開発者ブログ


Title 実例で納得! インターフェースの使い所
  • 2025年4月17日
  • maruo.shimohira
実例で納得! インターフェースの使い所

インターフェースってどうやって使うの?

インターフェースはどのように使うべきものだろう?

初学者の方がよく思う疑問だと思います。

検索してみても、なんとなく分かったけど具体的な使用例が浮かばない。 ← コレあると思います。

ようやく使いどころが腑に落ちたので、私が開発で直面した実例をもとに解説してみます。

インターフェースの使い所

早速ですが、インターフェースの使い所

「やりたい事は同じだけどそれぞれの実装が異なる時」

これでイメージできるでしょうか?

抽象的で分かりづらいですよね。

では実例として、私が趣味で開発している「株式取引用システム」を例に考えてみましょう。

大きな要件としては 1 つ。 「複数の証券会社に発注したい」


さて、どのように実装しましょうか。

証券会社毎に API のメソッドが異なるため、各証券会社クライアントサービスは必要そう?

各サービスを作ったとして、クライアント側ではどのように使えば良いのだろう?

全サービスのインスタンスを作っておき、証券会社タイプで場合分け??

それぞれのサービスのメソッドが違うのに、クライアント側で同じように使える?

実装できないことは無いけど、イマイチな感じがします。


なぜイマイチ?

例えば、新たな証券会社のクライアントが追加されるケースは容易に想像されます。

その場合、様々な場所に散らばった条件分岐等に抜け漏れなく実装にできるでしょうか?

このような問題を解決してくれるのがインターフェースです。

インターフェースとは

インターフェースにはお品書きが書かれてます。

インターフェースの実装クラスには、お品書きに書かれたプロパティやメソッドが必ず実装されます。

お品書きの実装が強制されるというのがミソで、クラスが変わっても同じような振る舞いをするというのはこの決まり事によるものです。

例えば・・・

証券会社に関係なくほしい機能としては大まかに 3 つ。

  • ログインメソッド
  • 発注メソッド
  • 口座残高取得メソッド

今回の例では、インターフェースを以下の通り実装しました。

public interface IBrokerService
{
    public Task LoginAsync(string userId, string password);  // ログインメソッド
    public Task OrderAsync(string stockCode, int quantity, int price); // 発注メソッド
    public Task GetAccountBalanceAsync(); // 口座残高取得メソッド
}

インターフェースの使い方

インターフェースを作るだけでは何もできません。

IBrokerService インターフェースを継承したそれぞれの証券会社ごとのサービスを実装します。

public class SpyClientService: IBrokerService // SPY 証券用クライアントサービス
{
    public Task LoginAsync(string userId, string password)  // ログインメソッド
    {
        // パスワード認証用の実装
    };

    public Task OrderAsync(string stockCode, int quantity, int price) // 発注メソッド
    {
        // 手数料は発注金額の0.5%
        // 日本株のみ発注可能
    };

    public Task GetAccountBalanceAsync() // 口座残高取得メソッド
    {
        // 省略
    };

}

public class NonomuraClientService : IBrokerService // 野々村証券用クライアントサービス
{
    public async Task LoginAsync(string userId, string password)
    {
        return // 認証無し
    }

    public async Task OrderAsync(string stockCode, int quantity, int price)
    {
        // 手数料は発注金額の1.0%
        // 米国株のみ発注可能
    }

    public async Task GetAccountBalanceAsync()
    {
        // 省略
    };
}

このように、証券会社ごとに実装はバラバラでも、

クライアント側では 「同じように扱える」 のがインターフェースの強みで、

この性質を「ポリモーフィズム(多態性)」とよびます。

実装は異なるが、やりたいことは同じ。

これらをインターフェースで縛っておくことで、利用者は迷わずに呼び出せるのです。

ファクトリメソッド

では、これらのインターフェース実装をどのように使用したらよいでしょうか。

証券会社によって勝手にクライアントを切り替えて使用できれば便利な感じがしませんか?

例えば、画面側で発注が行われ,以下のようなリクエストを受け取ったとします。

例:野々村証券で 銘柄 139A0 を 500円 で 100株 発注
{
    brokerType: "Nonomura",
    code: "139A0",
    price: 500,
    amount: 100
}

サーバの発注メソッドで、brokerType によって動的にクライアントサービスを選んでくれれば便利ですよね。

ただ、brokerType によって if 分岐でクライアントを分けるような実装では、知らず知らずのうちに実装漏れを起こし、バグとなるかもしれません。

こうした場合に使うのが「ファクトリメソッド」です。

ファクトリメソッドは、タイプによって必要なサービスのインスタンスを返してくれるものです。

以下は、証券会社タイプ(BrokerType)を受け取り、対応するクライアントサービスのインスタンスを返す例です。

public static class BrokerServiceFactory
{
    public static IBrokerService Create(BrokerType type) => type switch
    {
        BrokerType.Spy => new SpyClientService(),
        BrokerType.Nonomura => new NonomuraClientService(),
        _ => throw new NotSupportedException("未対応の証券会社タイプです")
    };
}

このように、証券会社タイプを引数で受け取り、対応する証券会社サービスのインスタンスを返すことができるというわけです。


クライアント側では以下の様に、対応する証券会社のクライアントを取得することができます。

// ファクトリからサービス取得
IBrokerService brokerService = BrokerServiceFactory.Create(brokerType);

// 発注
await brokerService.OrderAsync(orderData);

このように、使用するサービスを動的に切り替える事ができます。

つまり、クライアント側ではどの証券会社かを意識する事なくサービスが利用できるようになる訳です。

証券会社が違ってもやりたい事は同じ発注という場合、インターフェースとファクトリメソッドを使うことでこのようにシンプルに実装する事ができました。

まとめ

インターフェースの使い所がイメージできたでしょうか?

今回の例のように、「やりたいことは同じだけど中身(実装)は違う」という場面でインターフェースは役立ちます。

  • 実装の違いを吸収し、共通の使い方を提供できる
  • 将来の拡張(新しい証券会社の追加など)に強い設計になる
  • クライアント側のコードをシンプルに保てる
  • テストやモックの差し替えも容易で、テストしやすくなる

このように、インターフェースをうまく使うことで、拡張性・保守性・可読性すべてをバランスよく保つことができます。

「インターフェースっていつ使うの?」と感じていた方も、ぜひ自分の開発で活用してみてください!