Composite Patternとは
Composite Patternは木構造を伴う再帰的なデータ構造を表すことができます。同じインタフェースを持つ枝と葉が、再帰的な木構造を実現するんですねー。ファイルとディレクトリの関係がまさにComposite Patternです。
Composite パターン Wikipedia
Composite Patternを実装するには
TypescriptでのComposite Patternの実装はinterfaceがあれば実現出来ます。登場人物はComponentとLeafとCompositeです。各要素をクラス図にしてみました。LeafとCompositeはComponentインタフェースを実現しています。CompositeはComponentを集約しています。
Component
LeafとCompositeで共通となるインタフェースです。
木構造を実現する為の機能と、Leaf、Compositeが提供する機能を定義します。
Leaf
木の末端である葉を表すクラスです。
Composite
木の枝を表すクラスです。内部に葉か枝を複数持ちます。Componentの内、主に子要素を操作する機能を実現します。
Composite Patternの実装
何を作るか
ファイルとディレクトリを模した構造を作ってみます。共通のインタフェースであるComponentとファイルを表すItemクラス、ディレクトリを表すDirectoryクラスで構成されています。木構造のrootにDirectoryクラスを配置し、addメソッドでItemかDirectoryを追加して利用します。
Componentが子要素を持つDirectoryクラスか、葉であるItemかを判定する為のisItemメソッドを用意しました。このメソッドによってDirectory,Itemを判定し、再帰処理に利用します。
Componentインタフェースには子要素を操作するメソッドがいくつかあります。Itemクラスではそれらを利用しないので、呼び出した場合は例外を送出する様にしました。例外以外にも無効な値を返却するという方法も考えられます。
実装
//Composite Pattern //component interface Component{ add(child:Component):bool; remove(child:Component):bool; getChildren():Component[]; getName():string; isItem():bool; } //leaf class Item implements Component { constructor(private name: string){ } add(child:Component):bool{ throw new Error("this object is Item."); } remove(child:Component):bool{ throw new Error("this object is Item."); } getChildren():Component[]{ throw new Error("this object is Item."); } getName():string{ return this.name; } isItem():bool{ return true; } } //composite class Directory implements Component{ items:Component[]; constructor(private name: string){ this.items = new Array(); } add(child:Component):bool{ this.items.push(child); return true; } remove(child:Component):bool{ for (var i : number = this.items.length - 1; i >= 0; i--) { if(this.items[i].getName() === child.getName()){ this.items.splice(i, 1); i++; } } return true; } getChildren():Component[]{ return this.items; } getName():string{ return this.name; } isItem():bool{ return false; } }
ソースはこちら
https://github.com/sys1yagi/gof_design_pattern_implemented_in_Typescript/tree/decorator_pattern/src/03.Composite%20Pattern
動作
Composite Patternを用いた木構造でファイルとディレクトリを構成し、再帰的に木を走査して全要素を表示するサンプルです。子要素はpaddingを付けるようにしています。簡単に階層構造を表現出来ます。
Composite Patternの何がおいしいか
Composite PatternはComponentを再帰的に集約する点が拡張性を高めています。今回はConpositeとItemの二つの構成でしたが、ConpositeやItemの種類を増やしたりする事も容易に出来ます。DSLを作る為のInterpreter PatternもComposite Patternの一種です。
終わりに
Webではパンくずメニューや、サイドバーなどのメニューなどで使えると思います。その他にはフォームの入力チェックなんかにも使えるんじゃないかなーと思います。
次回はDecorator Patternを実装してみたいと思います。
0 件のコメント:
コメントを投稿