Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Getting started with C# SOLID Principles

2026年09月30日に「Dev.to」が公開したITニュース「Getting started with C# SOLID Principles」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

C#で、保守・拡張しやすいコードを書くための設計原則「SOLID」を学ぶ記事。データ操作、税計算、CSV出力などを機能ごとに分離し、インターフェースと依存性注入で組み合わせる実装例を通じて、変更に強いプログラムの作り方を解説。

出典: Getting started with C# SOLID Principles | Dev.to公開日:

ITニュース解説

この記事は、C#を使ってソフトウェアを開発する際に、高品質で保守しやすいシステムを構築するための重要な設計指針である「SOLID原則」について解説する。システムエンジニアを目指す初心者でも理解できるよう、提示された実際のコード例をもとに、それぞれの原則がどのように適用されているかを具体的に見ていこう。

まず、提示されているコードは、音楽機器(Instrument)を管理するシンプルなWebアプリケーションの一部だ。このアプリケーションは、楽器データのデータベースへの保存・取得、楽器の税金計算、楽器リストのCSVファイルへの出力、そしてこれらの機能をWebブラウザから操作するためのコントローラーで構成されている。これらの部品が互いに連携しながら一つのアプリケーションとして動いている。

1. データ管理を担う「InstrumentRepository」

InstrumentRepositoryというクラスは、楽器データをデータベースから取得したり、新しい楽器を追加したり、既存の楽器情報を更新・削除したりといった、データの永続化に関する責任だけを持っている。例えば、GetInstruments()で全ての楽器を取得したり、Add(Instrument i)で新しい楽器を保存したりする。このクラスがデータベース操作以外の、例えば税金計算やCSV出力といった処理まで担当してしまうと、変更が必要になった際に影響範囲が広がり、複雑になりがちだ。しかし、このコードではデータ操作のみに集中しているため、まさに「単一責任の原則 (Single Responsibility Principle - SRP)」が守られていると言える。一つのクラスは一つの責任だけを持つべきだという考え方だ。 さらに、IInstrumentRepositoryという「インターフェース」が定義されている点も重要だ。インターフェースは「こんな機能を提供します」という契約のようなもので、このインターフェースを実装するクラスは、その契約通りの機能を必ず提供しなければならない。コントローラーのような利用側は、具体的なInstrumentRepositoryクラスではなく、抽象的なIInstrumentRepositoryインターフェースに依存することで、将来データベースの仕組みが変わってInstrumentRepositoryの実装が変更されても、コントローラー側のコードを変更する必要がなくなる。これは「オープン・クローズドの原則 (Open/Closed Principle - OCP)」の適用例でもある。拡張には開かれていても、修正には閉じている状態を保てるということだ。

2. 税金計算を担う「ITaxCalculator」と「DefaultTaxCalculator」

ITaxCalculatorというインターフェースと、それを実装するDefaultTaxCalculatorクラスは、楽器の税金を計算するという特定の責任だけを担っている。CalculateTaxというメソッド一つだけを持ち、楽器の価格に0.15(15%)を掛ける計算を行っている。これもまた、税金計算という単一の責任に集中しているため、単一責任の原則が適用されている。 もし将来、税率が変わったり、特定の楽器に対して異なる税率を適用する必要が生じたりした場合でも、DefaultTaxCalculatorクラスの中身を変更するか、あるいはITaxCalculatorインターフェースを実装する新しい税金計算クラス(例えばLuxuryTaxCalculatorなど)を作成すればよい。既存の他のコード、特に税金計算の機能を利用しているコントローラーなどの部分を変更する必要がないため、これもオープン・クローズドの原則に則った設計と言える。また、ITaxCalculatorという小さく具体的なインターフェースは、税金計算が必要なクライアントに余分な情報を提供しないため、「インターフェース分離の原則 (Interface Segregation Principle - ISP)」にも貢献している。

3. CSVファイル出力を行う「ICsvExporter」と「CsvExporter」

ICsvExporterインターフェースとCsvExporterクラスは、楽器のリストをCSV形式の文字列に変換するという責任のみを担当している。ExportInstrumentsCsvメソッドがその役割だ。ここでも、CSV出力という単一の責任が明確であり、単一責任の原則が守られている。 もし、将来的にCSVではなくJSONやXMLなど、別の形式でデータを出力する機能が必要になった場合でも、ICsvExporterを実装する新しいエクスポータークラス(例えばJsonExporterなど)を追加するだけで対応できる。既存のCsvExporterやそれを利用するコントローラーのコードを修正する必要がないため、これもオープン・クローズドの原則の優れた適用例となる。このインターフェースも小さく、クライアントがCSV出力以外の不要なメソッドに依存しないため、インターフェース分離の原則にも合致している。

4. Webリクエストを処理する「InstrumentsController」

InstrumentsControllerは、Webアプリケーションにおける司令塔のような役割を果たすクラスだ。ユーザーがWebブラウザから「楽器の一覧を見たい」「特定の楽器の詳細を見たい」「新しい楽器を追加したい」「楽器リストをCSVでダウンロードしたい」といったリクエストを送ってきたときに、それらを適切に処理する。 このコントローラーの注目すべき点は、InstrumentRepositoryやTaxCalculator、CsvExporterといった具体的なクラスのインスタンスを自分自身で作成していないことだ。代わりに、コンストラクタでIInstrumentRepository、ICsvExporter、ITaxCalculatorというインターフェースの形でこれらを受け取っている。 例えば、Indexアクション(メソッド)では_repository.GetInstruments()を使って楽器データを取得し、Detailsアクションでは_taxCalculator.CalculateTax()で税金を計算し、Exportアクションでは_exporter.ExportInstrumentsCsv()を使ってCSVデータを作成している。 このように、コントローラーが高レベルのモジュール(より抽象的なビジネスロジックに近い部分)であり、IInstrumentRepositoryやICsvExporter、ITaxCalculatorが低レベルのモジュール(より具体的な実装に近い部分)であるとすると、コントローラーは具体的な低レベルモジュールに直接依存せず、抽象的なインターフェースに依存している。これは「依存関係逆転の原則 (Dependency Inversion Principle - DIP)」と呼ばれる重要な原則の適用例だ。この原則により、高レベルモジュールと低レベルモジュールの結合度が低くなり、変更に強く、テストしやすいシステムになる。

5. 依存性の注入を設定する「program.cs」

program.csファイルは、アプリケーションの起動時に必要な設定を行う場所だ。ここで特に重要なのが、builder.Services.AddScoped<IInstrumentRepository, InstrumentRepository>();のような記述だ。これは「依存性の注入(Dependency Injection - DI)」と呼ばれる仕組みを設定している部分で、「もしどこかのクラスがIInstrumentRepositoryが必要だと要求したら、具体的なInstrumentRepositoryクラスのインスタンスを提供してください」という指示をアプリケーションの実行環境(DIコンテナ)に与えている。 これにより、例えばInstrumentsControllerがIInstrumentRepositoryをコンストラクタで要求したとき、DIコンテナが自動的にInstrumentRepositoryのインスタンスを生成し、コントローラーに渡してくれる。コントローラー自身はどの具体的なクラスが使われているかを知る必要がなく、抽象的なインターフェースだけを知っていればよい。 このDIの仕組みは、依存関係逆転の原則を具体的に実現するための強力なツールであり、各コンポーネントが独立して機能し、互いに疎結合な(あまり強く結びついていない)関係を保つのに役立つ。これにより、特定のコンポーネントの変更が他の広範囲に影響を与えることを防ぎ、システムの保守性や拡張性を大幅に向上させる。

SOLID原則のまとめ

このコード全体を通して、SOLID原則がどのように適用されているかを見てきた。それぞれの原則は独立しているが、互いに連携し合い、より良いソフトウェア設計を導く。

  • 単一責任の原則 (SRP):一つのクラスはただ一つの責任を持つべきだ。InstrumentRepositoryはデータ永続化、ITaxCalculatorは税金計算、ICsvExporterはCSV出力、InstrumentsControllerはWebリクエスト処理と、それぞれが役割を明確に分担している。
  • オープン・クローズドの原則 (OCP):ソフトウェアのエンティティ(クラス、モジュールなど)は拡張に対しては開かれており、修正に対しては閉じられているべきだ。新しい機能が必要な場合でも、既存のコードを修正するのではなく、新しいコードを追加する形で対応できる。ITaxCalculatorやICsvExporterの例がそれだ。
  • リスコフの置換原則 (LSP):基底型(インターフェース)のオブジェクトは、派生型(実装クラス)のオブジェクトで置き換え可能でなければならない。この原則により、インターフェースを利用する側は、具体的な実装が何であるかを気にせず、インターフェースの契約通りに振る舞うことを期待できる。
  • インターフェース分離の原則 (ISP):クライアントが依存するインターフェースは、そのクライアントにとって必要不可欠なものだけを含むべきだ。大きすぎる「万能インターフェース」ではなく、小さく具体的なインターフェースを複数定義することで、不要なメソッドへの依存を防ぎ、設計の柔軟性を高める。IInstrumentRepository, ITaxCalculator, ICsvExporterがそれぞれ独立したインターフェースであるのはこの原則に沿っている。
  • 依存関係逆転の原則 (DIP):高レベルのモジュールは低レベルのモジュールに依存せず、両方とも抽象(インターフェース)に依存すべきだ。また、抽象は詳細に依存すべきではなく、詳細は抽象に依存すべきだ。InstrumentsControllerが具体的な実装クラスではなく、IInstrumentRepositoryなどのインターフェースに依存し、program.csでその具体的な実装が注入されることで、この原則が実現されている。

これらの原則を意識してコードを書くことで、後から機能を追加したり、不具合を修正したりする際の作業がずっと楽になる。また、チーム開発においても、各担当が自分の責任範囲に集中しやすくなるため、効率的な開発が期待できる。SOLID原則は、変化に強く、持続可能なシステムを構築するための強力な指針となるだろう。

関連コンテンツ

関連IT用語