+5

Blog#98: 依存性注入のマジックを解き放つ:初心者向けガイド ・「Dependency Injection (DI)」

image.png

この記事の主な目的は、日本語レベルを上げるのを手伝うことです。ソフトウェア開発に関連する概念や知識なとを紹介するために簡単な日本語を使います。ITの知識に関しては、インターネット上でもっとよく説明されているかもしれませんが、この記事の主な目標はまだ日本語を学ぶことです。


こんにちは、私はトゥアンと申します。東京からフルスタックWeb開発者です。 将来の有用で面白い記事を見逃さないように、私のブログをフォローしてください。

JavaScriptスキルを次のレベルに上げたいですか? コードをもっと整理しやすく、テストしやすく、モジュール化しやすい方法を学びたいですか? 幸運なことに、今日は依存性注入の世界に没頭しましょう!

依存性注入は、コード内の異なるオブジェクトの関係を管理するための強力なデザインパターンです。 コードをより柔軟にし、理解しやすくするのに役立ちます。 これは、シリアスなJavaScript開発者にとって必須のテクニックです。

この記事では、簡単な日本語で依存性注入の基本を解説し、それがどのようにコードをより強力にするかを例を用いて説明します。さらに、各例に対してコードサンプルを掲載し、実際にどのように動作するかを理解するのを手助けします。

それでは、早速始めて、依存性注入の力を引き出す方法を学びましょう!

依存性注入とは

依存性注入は、オブジェクトがその仕事をするために必要なものを提供する方法です。これらのものは依存関係と呼ばれます。 例を見てみましょう。

class Dog {
  constructor() {
    this.barkSound = 'woof';
  }
  
  bark() {
    console.log(this.barkSound);
  }
}

const myDog = new Dog();
myDog.bark(); // Output: 'woof'

例えば、「Dog」というクラスがあり、「bark」というメソッドで音を出します。音は「barkSound」というプロパティに保存されます。「barkSound」プロパティはコンストラクタメソッドの中で作られていることに注意してください。ハードコーディングされており、変えたい場合はクラスの中に入って変更する必要があります。

これは小さなプロジェクトで問題にならないかもしれませんが、プロジェクトが大きくなり、このようなクラスが多くなった場合は、メンテナンスするのが難しくなります。また、barkメソッドをテストする場合は、毎回新しいインスタンスを作成する必要がありますが、それは負担になります。

依存性注入

この問題を解決するために、依存性注入がどのように役立つのか見てみましょう。

class Dog {
  constructor(barkSound) {
    this.barkSound = barkSound;
  }
  
  bark() {
    console.log(this.barkSound);
  }
}

const myDog = new Dog('woof');
myDog.bark(); // Output: 'woof'

今度は、「barkSound」プロパティをクラスの中で作らず、コンストラクタに引数として渡します。これにより、犬の鳴き声を変更することができ、クラスを変更することなく、barkメソッドをテストすることができるようになります。

依存性注入は、多様な方法で使用できる強力なパターンです。ここでは、どうやって使うかの例を見せます。

1. テスト

前に述べたように、依存性注入はコードに対する自動テストを書きやすくします。 依存関係のテスト版を作成し、テストしたいオブジェクトに渡すことができます。 このようにすることで、依存関係をテストすることなく、オブジェクトをテストすることができます。

class Dog {
  constructor(dog) {
    this.dog = dog;
  }

  bark() {
    console.log(this.dog.barkSound);
  }
}

class SilentDog {
  constructor() {
    this.barkSound = "Meo Mew";
  }

  bark() {
    console.log(this.barkSound);
  }
}

const testDog = new Dog(new SilentDog());
testDog.bark(); // Output: 'Meo Mew'

2. 設定

依存性注入を使用して、アプリケーションの設定をコードから分離することができます。 このようにすることで、コード自体を変更せずにアプリケーションの振る舞いを変更することができます。

class Dog {
  constructor(config) {
    this.barkSound = config.barkSound;
    this.color = config.color;
  }

  bark() {
    console.log(this.barkSound);
  }
}

const config = {
  barkSound: "woof",
  color: "brown",
};

const myDog = new Dog(config);
myDog.bark(); // Output: 'woof'
console.log(myDog.color); // Output: 'brown'

3. プラグイン:

依存性注入を使用して、ユーザーがコードを変更せずに新しい機能をアプリケーションに追加できるようにすることができます。 例えば、ユーザーが自分自身のプラグインを書き、アプリケーションに追加できるプラグインシステムを作成することができます。

class MyApp {
  constructor(plugins) {
    this.plugins = plugins;
  }

  run() {
    this.plugins.forEach((plugin) => plugin.run());
  }
}

class MyPlugin {
  run() {
    console.log("This is my plugin");
  }
}

const app = new MyApp([new MyPlugin()]);
app.run(); // Output: 'This is my plugin'

4. データアクセス

依存性注入を使用して、アプリケーションのデータアクセスコードをコードから分離することができます。 これにより、アプリケーションがデータを格納し、取り出す方法を変更することができるので、コードのほかの部分を変更する必要がなくなります。

const db = {};

class Dog {
  constructor(dataAccess) {
    this.dataAccess = dataAccess;
  }

  save() {
    this.dataAccess.save(this);
  }

  bark() {
    console.log(this.barkSound);
  }
}

class LocalStorageDataAccess {
  save(dog) {
    db[JSON.stringify(dog)] = JSON.stringify(dog);
  }
}

const myDog = new Dog(new LocalStorageDataAccess());
myDog.barkSound = "woof";
myDog.save();
console.log(db);
// {
//  '{"dataAccess":{},"barkSound":"woof"}': '{"dataAccess":{},"barkSound":"woof"}'
// }

5. アーキテクチャ:

依存性注入を使用して、アプリケーションのレイヤードアーキテクチャを作成できます。これにより、コードをモジュール化し、理解しやすくすることができます。

class Dog {
  constructor(barkSound, color) {
    this.barkSound = barkSound;
    this.color = color;
  }
  bark() {
    console.log(`My dog barks with ${this.barkSound} and the color is ${this.color}`);
  }
}
class DogFactory {
  createDog(type) {
    switch (type) {
      case "GoldenRetriever":
        return new Dog("woof", "golden");
      case "Bulldog":
        return new Dog("bark", "white");
    }
  }
}
const factory = new DogFactory();
const goldenRetriever = factory.createDog("GoldenRetriever");
goldenRetriever.bark(); 
// Output: 'My dog barks with woof and the color is golden'

const bulldog = factory.createDog("Bulldog");
bulldog.bark(); 
// Output: 'My dog barks with bark and the color is white'

この例では、「DogFactory」というクラスが依存性注入パターンを使用して異なるタイプの犬を作成します。「barkSound」や「color」のようなプロパティを「Dog」クラスに依存関係として渡します。 このようにすることで、「Dog」クラスを変更することなく、異なるタイプの犬を作成することができます。 また、犬を作成することと「Dog」クラスを分けることができます。

結論

依存性注入は、JavaScriptのコードをモジュール化し、テストしやすく、柔軟にするための強力なパターンです。 コードの懸念を分離することで、理解しやすく、メンテナンスしやすくなります。 依存性注入を使用することで、よりテストしやすくモジュール化されたコードを作成し、コード内の異なるオブジェクトの関係を管理することができます。

最初は少し複雑に感じるかもしれませんが、基本を理解すれば、コーディングの旅が簡単になります。ここで示した例は簡単なものであり、プロジェクトでもっと高次の段階に取り入れることができます。大規模で複雑なコードベースを扱う場合、依存性注入は非常に役立つことが証明されるでしょう。

最後

いつもお世話になっています。この記事を楽しんで、新しいことを学べたら嬉しいです。

次の記事でお会いしましょう!この記事が気に入ったら、私を応援するために「いいね!」を押して登録してください。ありがとうございました。


この記事の主な目的は、日本語レベルを上げるのを手伝うことです。ソフトウェア開発に関連する概念や知識なとを紹介するために簡単な日本語を使います。ITの知識に関しては、インターネット上でもっとよく説明されているかもしれませんが、この記事の主な目標はまだ日本語を学ぶことです。

Ref


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.