📦
デザインパターン:Compositeパターン
これは何?
オブジェクトを木構造として扱い、個々と全体を同一視して扱うためのパターン。
箱と物を同じインターフェースで扱えたら複雑性減るよねマン
何が嬉しいのか
問題
ファイル管理アプリで多階層のファイルを一括削除するとき、オブジェクトごと(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)で解決したりする
その他の推しポイント
- 新しい要素を追加するときも、既存の要素を破壊することなく導入可能
動く実装例
Discussion