0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

プログラムの依存性と依存性注入

Posted at

プログラムの依存性とは

プログラムの依存性とは、ある要素(モジュール、ライブラリ、関数など)が、他の要素の機能やデータに依存していることを指します。
依存している要素が変更されると、依存している側のプログラムにも影響が出る可能性があります。

依存性の問題点

プログラムの依存性は、以下のような問題を引き起こします。

  • 変更の難しさ
    依存している要素を変更する場合、依存している側のプログラムにも変更が必要となるため、変更が難しくなります。
  • テストの難しさ
    依存している要素をモックやスタブで置き換えてテストすることが難しくなります。
  • 再利用性の低さ
    依存している要素が異なる環境で利用できない場合、プログラムを再利用することができなくなります。

これらの依存性の問題を解決するために、依存性の注入という手法が使用されます。

依存性の注入とは

依存性の注入(Dependency Injection)とは、オブジェクトの依存関係を外部から注入し、コードの柔軟性と再利用性を高めるための設計パターンのことを指します。
言葉で説明されてもよくわからないと思うので、実際にコードを書いてみます。

通常の依存関係

// UserRepository.js
class UserRepository {
  getUser(userId) {
    // データベースからユーザー情報を取得する
    return { id: userId, name: 'John Doe' };
  }
}

// UserService.js
class UserService {
  constructor() {
    this.userRepository = new UserRepository();
  }

  getUserName(userId) {
    const user = this.userRepository.getUser(userId);
    return user.name;
  }
}

// 使用例
const userService = new UserService();
console.log(userService.getUserName(1)); // "John Doe"

従来の依存関係では、UserServiceクラスはUserRepositoryクラスのインスタンスを直接生成しています。これは、UserServiceクラスがUserRepositoryクラスの具体的な実装に依存していることを意味します。

この場合、UserServiceクラスを使用するには、UserRepositoryクラスが利用可能である必要があります。また、UserRepositoryクラスの具体的な実装が変更されると、UserServiceクラスのコードにも変更が必要になる可能性があります。

依存性注入を使った例

// UserRepository.js
class UserRepository {
  getUser(userId) {
    // データベースからユーザー情報を取得する
    return { id: userId, name: 'John Doe' };
  }
}

// UserService.js
class UserService {
  constructor(userRepository) {
    this.userRepository = userRepository;
  }

  getUserName(userId) {
    const user = this.userRepository.getUser(userId);
    return user.name;
  }
}

// 使用例
const userRepository = new UserRepository();
const userService = new UserService(userRepository);
console.log(userService.getUserName(1)); // "John Doe"

一方、依存性注入では、UserServiceクラスはUserRepositoryクラスのインスタンスを外部から注入されます。これは、UserServiceクラスがUserRepositoryクラスの具体的な実装に依存せず、任意のUserRepository実装を受け取ることができることを意味します。

UserServiceクラスのコンストラクタにUserRepositoryクラスのインスタンスを渡すことで、UserServiceクラスはUserRepositoryクラスの具体的な実装に依存せず、どのようなUserRepository実装でも動作することができます。

さらに、依存性注入を利用することで、モック(ダミー)オブジェクトを使用してテストが簡単に行えます。

依存性注入を利用しない場合のテストコード

const { UserService } = require('./UserService');

// テスト例
describe('UserService', () => {
  it('should return the user name', () => {
    const userService = new UserService();

    const userName = userService.getUserName(1);
    expect(userName).toBe('John Doe'); // 実際のデータベースアクセスが行われる
  });
});

テスト対象であるUserServiceクラスだけでなく、依存しているUserRepositoryクラスなども考慮する必要があります。実際のデータベースアクセスや外部システムとの連携などの処理がテスト結果に影響するため、テストコードが複雑になりやすく、メンテナンスも困難になります。

依存性注入を用いたテストコード

// UserService.test.js
const { UserService } = require('./UserService');

class MockUserRepository {
  getUser(userId) {
    // テスト用のダミーデータを返す
    return { id: userId, name: 'Mock User' };
  }
}

// テスト例
describe('UserService', () => {
  it('should return the user name', () => {
    const mockUserRepository = new MockUserRepository();
    const userService = new UserService(mockUserRepository);

    const userName = userService.getUserName(1);
    expect(userName).toBe('Mock User');
  });
});

テスト対象であるUserServiceクラスのみを独立してテストすることができます。テスト対象以外のクラス(UserRepositoryクラスなど)はモックやスタブと呼ばれる偽のオブジェクトで置き換えるため、実際のデータベースアクセスや外部システムとの連携などを考慮する必要がありません。

依存性注入の利点

  • テストの容易さ
    テストを行う際に、実際のUserRepositoryクラスではなく、モックやスタブと呼ばれる偽のオブジェクトを注入することで、UserServiceクラス単体でテストしやすくなります。
  • 変更の容易さ
    UserRepositoryクラスを変更する場合、UserServiceクラスのコードを変更する必要がありません。UserServiceクラスは、UserRepositoryクラスのインターフェースだけに依存しているため、UserRepositoryクラスの具体的な実装が変更されても、UserServiceクラスは動作し続けます。
  • 再利用性の高さ
    UserServiceクラスは、UserRepositoryクラス以外のデータベースやファイルなどからユーザー情報を読み取るUserRepositoryクラスを注入することで、再利用することができます。

まとめ

最後までご覧いただき、ありがとうございました。

依存性注入(DI)は、プログラムの依存性が引き起こす変更やテストの困難さ、再利用性の低さを解決するための重要な設計パターンです。DIを用いることで、クラスの依存を外部から注入し、コードの柔軟性と再利用性を高め、テストのしやすさや変更の容易さも向上します。

依存性を考慮し、適切な設計パターンを選択していくことで、より効果的なコードを実現していきましょう。

ご意見やご指摘がございましたら、ぜひお聞かせください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?