Compositeパターンに応用できそうなものとして、
HTMLタグなんかいいかと思いコーディングしてみました。
クラス図
説明
Compositeパターンは再帰構造を実現するパターンです。
一方(Child)が終端で、もう一方(Parent)が再帰構造を持つ形になっています。
ParentはHtmlComponentを集約(実装上ではListで保持)しています。
こうすることで、ParentとHtmlComponentが再帰的な関係持つようになります。
|
|こんな感じ
↓
Parent(HtmlConponent) – Parent(HtmlConponent) – Parent(HtmlConponent) …
└ Child(HtmlConponent)
ParentもChildもHtmlComponentを継承しており、
同じメソッド(create(String indent))で呼び出すことができます。
ただし、振る舞いが若干異なります。
Parentでは再帰構造を実現するために、保持しているHtmlComponent型のリストをIteration(反復処理)します。
IterationされたHtmlComponentの要素は、ParentまたはChildを呼び出す再帰処理になります。
ChildではParentの反復処理が無いだけで、通常の処理が行われます。
ソースコード
HtmlComponent (abstract Class)
ParantとChildの基底クラス(継承元クラス)
create(String indent)は、ParentとChildで実装するメソッドで、
create()はデフォルト動作を実現するメソッドとして実装する。
インデントの指定なし(create())で呼び出すか、
インデントの指定あり(create(String indent))で呼び出すかということになる。
あと、タグと閉じタグはParentとChildで同じであるため、
基底クラスであるこのクラスで実装しておけばよい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package composite.html; public abstract class HtmlComponent { protected String _tag; abstract public String create(String indent); public String create() { return create(""); } public String tag() { return "<" + _tag + ">"; } public String closeTag() { return "</" + _tag + ">"; } } |
Parent (Class)
create(String indent)メソッドでタグを生成するが、
その際に引数で渡されたインデントを設定する。
また、タグと閉じタグの間に再帰処理を実装することで、
下層のタグを再帰的に作成することになる。
これがCompositeパターンの要点である、
「保持している抽象的な要素を再帰処理する」部分となる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
package composite.html; import java.util.ArrayList; import java.util.List; public class Parent extends HtmlComponent { private List<HtmlComponent> _htmlComponents = new ArrayList<HtmlComponent>(); public Parent(String tag) { _tag = tag; } @Override public String create(String indent) { String tagCompsite = ""; tagCompsite += indent + tag() + System.lineSeparator(); for(HtmlComponent htmlComponent: _htmlComponents) { tagCompsite += htmlComponent.create(indent + " "); } tagCompsite += indent + closeTag() + System.lineSeparator(); return tagCompsite; } public void add(HtmlComponent htmlComponent) { _htmlComponents.add(htmlComponent); } public void remove(HtmlComponent htmlComponent) { _htmlComponents.remove(htmlComponent); } } |
Child (Class)
Childは下層を持たないため、create(String indent)メソッドは単純に結果を返すのみとなる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package composite.html; public class Child extends HtmlComponent { public Child(String tag) { _tag = tag; } @Override public String create(String indent) { return indent + tag() + closeTag() + System.lineSeparator(); } } |
Main (実行)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package composite.html; public class Main { public static void main(String...strings) { Parent html = new Parent("html"); Parent body = new Parent("body"); Parent title = new Parent("title"); Parent header = new Parent("header"); Parent div1 = new Parent("div1"); Parent div2 = new Parent("div2"); Child p = new Child("p"); html.add(header); html.add(title); html.add(body); body.add(div1); div1.add(div2); div2.add(p); html.remove(header); // 削除 String tags = html.create(); System.out.println(tags); } } |
実行結果
追加した各要素の構造でインデントが付与されて表示される。
削除したheaderは表示されていない。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<html> <title> </title> <body> <div1> <div2> <p></p> </div2> </div1> </body> </html> |
参考
Interfaceで実装する例が書かれている。
Wiki – Composite パターン
抽象クラスで実装する方法が書かれている。
デフォルトメソッドの実装もここを参考にしました。
Qiita – デザインパターン ~Composite~
言わずと知れたデザインパターンの良書(全23パターンが網羅されている)
書籍 – 増補改訂版 Java言語で学ぶデザインパターン入門