📦

デザインパターン:Compositeパターン

2024/07/19に公開

これは何?

オブジェクトを木構造として扱い、個々と全体を同一視して扱うためのパターン。

箱と物を同じインターフェースで扱えたら複雑性減るよねマン

何が嬉しいのか

問題

ファイル管理アプリで多階層のファイルを一括削除するとき、オブジェクトごと(File, Folder)に削除のロジックが独立している。異なる種類のオブジェクトを一元的に扱う際の処理が複雑になり、メンテナンスも大変

class DocumentFile {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  deleteFile() {
    console.log(`Deleting file: ${this.name}`);
  }
}

class Folder {
  name: string;
  files: File[] = [];
  folders: Folder[] = [];
  constructor(name: string) {
    this.name = name;
  }
  deleteFolder() {
    console.log(`Deleting folder: ${this.name}`);
    for (const file of this.files) {
      file.deleteFile();
    }
    for (const folder of this.folders) {
      folder.deleteFolder();
    }
  }
}

解決

deleteと言う関数を持つ共通のインターフェースを定義

FileもFolderも同一視して扱えることになるので、Folder.deleteが劇的にシンプルに

// Component インタフェース
interface FileSystemComponent {
  name: string;
  delete(): void;
}

// Leaf クラス
class DocumentFile implements FileSystemComponent {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  delete() {
    console.log(`Deleting file: ${this.name}`);
  }
}

// Composite クラス
class Folder implements FileSystemComponent {
  name: string;
  children: FileSystemComponent[] = [];
  constructor(name: string) {
    this.name = name;
  }
  delete() {
    console.log(`Deleting folder: ${this.name}`);
    for (const child of this.children) {
      child.delete();
    }
  }
}

※機能が大きく異なるオブジェクトの共通インターフェース作成は難しく、理解も困難

→Factory, Builderパターンで解決したり、振舞関連パターン(Visitor, Strategy)で解決したりする

その他の推しポイント

  • 新しい要素を追加するときも、既存の要素を破壊することなく導入可能

動く実装例

https://www.typescriptlang.org/play?#code/PTAEGEHsFsAdIHYFMEBdSBKGQzwyH6GQqwyDlDID8MgnQwBQAlmkgE4BmAhgMZKgBiFANkgMoCeAZ1RJoUOIhToA3mVCgEDaEgBcoITSoBzANyzQAEyTdhACgCUqgG6QK+3QF8yZEKAAySBnVCB6hkCXDOSZOBgEBUAARSCYAVyU0Dm5QCjhuWNRQ+N5BYVEYeGQ0UBk5BSVVdS1dOSZEdSimVEgaExKVNVQNBE0zQr05VAALCgEAOhbQAF55RSRK0Ec5Q2Mkcx65KprIbmHOSE0TAAMwoyRULVA6LlaAEikBodHp+32zWcdHZzAxeAEKYR9-MiBYLpTaGGiJZIiSTpS78IQiL4SApFKalNodHR6JiDTj6GgoVQZOHZRH5VAAbQAuhNQFTZtUELV6o1mtMyu0tN0UX1BiMxpMWq89Ax9PoTNiuPpCbCsgjckjUFzeqA7iMJbj8QhhrAogJ+uKcfoXnp5gZjqYlWtQAyBJskNtdgcjsYznRQbRVDdVQ8lE9jVa3eDxTV0Or9KBIF5vWHNZardbDcNFidlv61qa3k4XIBWhiwgHWGQDXDIA7BkA-vKAEQZAJ2mgJDoBokEg6AFSAA7ux3U0AOR1hsd4029D9GCsJuttjtkwdwdKXu6fugABWkH6CBpyFH447i+XM+rjPQF24AEZVy3wpEYpIMhOD0hD8NUAAPVA7uc3gBMJ9bEWiqSvHff95PjuZBblqIpijeh7GqBwzgSY77GlO9pwaBxrdqgsGiiYSHGh8tb1qgeCAJUMBaAAMMgAWDIAugxFoAtHKANVxgBJDIAUkqACZpZDoUm5qptoQA

Tokyo, inc. Engineers

Discussion