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

image.png

こんにちは、私は東京からのフルスタックWebデベロッパーであるTUANです。

今後の便利で面白い記事を見逃さないように、私のブログをフォローしてください。

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メソッドをテストすることができるようになります。

依存性注入は、多様な方法で使用できる強力なパターンです。ここでは、実際の世界でどのように使用するかの5つの例を示します。

1. テスト

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

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

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

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

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

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

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. データアクセス

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

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

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

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

class LocalStorageDataAccess {
  save(dog) {
    localStorage.setItem("dog", JSON.stringify(dog));
  }
}

const myDog = new Dog(new LocalStorageDataAccess());
myDog.barkSound = "woof";
myDog.save();

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

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

いつものように、この記事を楽しんで新しいことを学んでいただけたと思います。

ありがとうございました。次の記事でお会いしましょう!

この記事が気に入ったら、いいねをして購読してサポートしてください。ありがとうございます。

NGUYỄN ANH TUẤN

Xin chào, mình là Tuấn, một kỹ sư phần mềm đang làm việc tại Tokyo. Đây là blog cá nhân nơi mình chia sẻ kiến thức và kinh nghiệm trong quá trình phát triển bản thân. Hy vọng blog sẽ là nguồn cảm hứng và động lực cho các bạn. Hãy cùng mình học hỏi và trưởng thành mỗi ngày nhé!

Đăng nhận xét

Mới hơn Cũ hơn