まずオブジェクト指向って何?
オブジェクト指向(OOP)は、ざっくり言うと、アプリとかの仕組みを「オブジェクト」っていう小さな部品の集合みたいにして組み立てるスタイルなの。これでコードが超見やすく、管理しやすくなるのよね~。
例として、例えば社員管理システムとか作るとするよ!こんな感じで、社員それぞれを「オブジェクト」にするわけ👇:
class Employee {
constructor(public name: string, public position: string) {}
work() {
return `${this.name} is working as a ${this.position}`;
}
}
const employee = new Employee("Taro", "Developer");
console.log(employee.work()); // → "Taro is working as a Developer"
社員(Employee)ってクラスから、個別の「社員オブジェクト」を作って使う感じ。これがオブジェクト指向の基本ノリね💼💖!
依存性の逆転(Dependency Inversion)とは?
依存性の逆転(DIP)は、めっちゃシンプルに言うと、「上のクラスも下のクラスも直接お互いに頼らず、抽象的なルール(インターフェースとか)を介してやり取りしようぜ!」って考え方。これでコードがゴチャゴチャせず、変更に強くなるの。
なぜ必要?
そのまま実装すると、コードが「具体的なクラス」にガッツリ依存しちゃって修正が超ダルくなるの!💦例えば「社員データ」をデータベースから取得するクラスがあったとして、実際に使うデータベースを変更したらコード全部直さなきゃ…ってなるのよ。それ絶対嫌じゃん?🤦♀️✨
DIPを使うと、データ取得の仕組みを「インターフェース(抽象)」で定義しておいて、どのデータベースでも柔軟に変更可能な感じになるの!
コード例:社員データ取得のシステム
「現場でありそう」なコードを書いてみたよ!👇
DIPを使わない場合(NG例)
class DatabaseService {
getEmployees() {
return ["Taro", "Hanako", "Jiro"];
}
}
class EmployeeManager {
private dbService: DatabaseService;
constructor() {
this.dbService = new DatabaseService();
}
listEmployees() {
return this.dbService.getEmployees().join(", ");
}
}
// 実行
const manager = new EmployeeManager();
console.log(manager.listEmployees()); // "Taro, Hanako, Jiro"
🌟 問題点:
EmployeeManagerがDatabaseServiceに直接依存しちゃってるから、データベースの仕組みを変えるとき(例えば、クラウドDBに切り替えたいとき)に修正が面倒すぎる💦。
クラウドDBを追加する場合
class EmployeeManager {
private dbService: any;
constructor() {
// 新しくCloudServiceを使う場合
this.dbService = new CloudService();
}
listEmployees() {
return this.dbService.getEmployees().join(", ");
}
}
// 実行例
const manager = new EmployeeManager();
console.log(manager.listEmployees()); // "Alice, Bob, Charlie"
今回はCloudServiceだけど、将来的に別のデータベース(例えばNoSQLとか)を使う場合も、また同じことを繰り返さなきゃいけない。
DIPを使う場合(GOOD例✨)
// 抽象(インターフェース)を定義
interface EmployeeRepository {
getEmployees(): string[];
}
// データベース用のクラス
class DatabaseService implements EmployeeRepository {
getEmployees(): string[] {
return ["Taro", "Hanako", "Jiro"];
}
}
// クラウド用のクラス(新しいデータソース)
class CloudService implements EmployeeRepository {
getEmployees(): string[] {
return ["Alice", "Bob", "Charlie"];
}
}
// EmployeeManagerは抽象に依存!
class EmployeeManager {
private repository: EmployeeRepository;
constructor(repository: EmployeeRepository) {
this.repository = repository;
}
listEmployees() {
return this.repository.getEmployees().join(", ");
}
}
// 実行
const dbManager = new EmployeeManager(new DatabaseService());
console.log(dbManager.listEmployees()); // "Taro, Hanako, Jiro"
const cloudManager = new EmployeeManager(new CloudService());
console.log(cloudManager.listEmployees()); // "Alice, Bob, Charlie"
🌟 良い点:
EmployeeManagerは具体的なDatabaseServiceやCloudServiceに依存せず、EmployeeRepositoryという抽象にだけ依存してる。
だから、データベースをクラウドに切り替えても、EmployeeManagerを一切修正せずに済むの!修正箇所が最小限で楽チン~💅✨。
ギャルポイント✨
DIPを意識すると、システム全体が「独立モジュール」みたいにスッキリまとまるから、チーム開発でもバチバチ強いコーディングができる!🌟
依存性を具体から抽象に変えることで、拡張性と柔軟性が爆上がり!これ、最強じゃない?💖
こんな感じでDIPを理解しておけば、業務でコードを書くときにもバッチリ活用できるし、めっちゃ「できるエンジニア」って感じ出せるよ~✨!他にも知りたいことがあったら、遠慮なく聞いてね!