依存性注入を使う理由
テストしやすくするため、構築と利用を分離します。
「依存性注入を使う理由」はCoddyKit上の無料Swift Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSwift Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Swift Academyコースには全4レッスンが含まれています。
依存性注入の理由
依存性注入(DI)とは、オブジェクトが必要とするものを自分で作成するのではなく、外部から渡すことです。これによりコンポーネント間の結合が弱まり、テストしやすくなります。
問題点:強い結合
型が協調オブジェクトを自分で生成すると、具体的なクラスに固定され、再構成したり単体でテストしたりできなくなります。
class Logger {
func log(_ m: String) { print("LOG: \(m)") }
}
class Service {
let logger = Logger() // hard-coded dependency
func run() { logger.log("running") }
}
Service().run()結合はテストを難しくする
Serviceが常に実際のLoggerを作成するため、テストではログ出力を取得したり偽物に置き換えたりできません。依存関係が外部から見えないためです。
class Logger { func log(_ m: String) { print(m) } }
class Service {
let logger = Logger()
func run() { logger.log("hello") }
}
// No way to swap Logger here.
Service().run()考え方:注入する
代わりに、依存関係を外部から渡します。どの実装を提供するかは呼び出し側が決めるため、Serviceはその実装を意識しなくて済みます。
class Logger { func log(_ m: String) { print("LOG: \(m)") } }
class Service {
let logger: Logger
init(logger: Logger) { self.logger = logger }
func run() { logger.log("running") }
}
Service(logger: Logger()).run()疎結合の利点
注入を使うと、同じServiceを本番でもテストでも、コードを変更せずに異なるロガーと組み合わせて使えます。
class Logger { var lines: [String] = []
func log(_ m: String) { lines.append(m) } }
class Service {
let logger: Logger
init(logger: Logger) { self.logger = logger }
func run() { logger.log("event") }
}
let l = Logger()
Service(logger: l).run()
print(l.lines)単一責任
DIは単一責任の原則を支えます。型は自分の役割に集中し、それ以外の関心事は注入された協調オブジェクトに委ねます。
struct Mailer { func send(_ to: String) { print("Mail to \(to)") } }
struct SignupFlow {
let mailer: Mailer
func register(_ email: String) { mailer.send(email) }
}
SignupFlow(mailer: Mailer()).register("a@b.com")柔軟性
オブジェクトを新しい形で組み合わせられます。配線はアプリの境界部分で行うため、中心となるコードを柔軟に保てます。
struct Engine { let power: Int }
struct Car {
let engine: Engine
func describe() { print("Power: \(engine.power)") }
}
Car(engine: Engine(power: 200)).describe()
Car(engine: Engine(power: 90)).describe()明示的な依存関係
依存関係を列挙するイニシャライザは、その型が必要とするものを正確に示します。内部で作成する隠れた依存関係では、その契約が見えなくなります。
struct Repo { func load() -> [Int] { [1, 2, 3] } }
struct Report {
let repo: Repo // visible dependency
func total() -> Int { repo.load().reduce(0, +) }
}
print(Report(repo: Repo()).total())構築よりも合成
DIでは、外部からオブジェクトを組み立てる方法を重視します。小さなコンポジションルートでオブジェクトグラフを構成し、それ以外のコードは必要なものを受け取るだけにします。
struct DB { func count() -> Int { 42 } }
struct Stats { let db: DB; func show() { print(db.count()) } }
// Composition root:
let app = Stats(db: DB())
app.show()大規模アプリだけのものではない
小さなプログラムでもメリットがあります。依存関係を注入すれば、追加のフレームワークなしで動作を差し替えられ、意図も明確になります。
struct Clock { func now() -> Int { 12 } }
struct Greeter {
let clock: Clock
func greet() { print(clock.now() < 12 ? "Morning" : "Afternoon") }
}
Greeter(clock: Clock()).greet()フレームワークは不要
SwiftのDIにライブラリは必要ありません。通常のイニシャライザとプロトコルで十分です。これからのレッスンでは、コンストラクタインジェクション、プロトコル、モックを扱います。
struct Adder { func add(_ a: Int, _ b: Int) -> Int { a + b } }
struct Calc {
let adder: Adder
func run() { print(adder.add(2, 3)) }
}
Calc(adder: Adder()).run()確認問題
依存性注入の中心となる考え方は何ですか。
まとめ
依存性注入では、協調オブジェクトを内部で構築するのではなく外部から提供するため、結合を減らし、依存関係を明確にし、テストを可能にします。Swiftではフレームワークは必要ありません。次は、最も一般的な形式であるコンストラクタインジェクションを見ていきます。
よくある質問
「依存性注入を使う理由」レッスンは無料ですか?
はい。「依存性注入を使う理由」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Swift Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Swift Academyコースには全4レッスンが含まれています。
「依存性注入を使う理由」で何を学びますか?
テストしやすくするため、構築と利用を分離します。 ブラウザで直接実行するハンズオンコードでSwift Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Swift Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのSwift Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「依存性注入を使う理由」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このSwift Academyレッスンでコードを書いて実行できますか?
はい。すべてのSwift Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。