JavaエンジニアがRubyでデザインパターンを学ぶ - Composite Pattern

# 概要
「Rubyによるデザインパターン」を読んでデザインパターンを勉強中。
Javaをやっていた人間としての目線で情報を整理してみます。

####他のデザインパターン
[Template Method Pattern](http://qiita.com/ksugimori/items/34e766e9bff4cfa62591)
[Strategy Pattern](http://qiita.com/ksugimori/items/f8773909ded7585c5d61)
[Observer Pattern](http://qiita.com/ksugimori/items/cff3501f6ac50120b4db)

# Composite Pattern

- 全体と部分を同一視する、というパターン
- 入れ物（Composite）と中身（Leaf または Composite）が同じインターフェースを持つことでツリーのような再帰的な構造を簡潔に表現できる

![png-2.png](https://qiita-image-store.s3.amazonaws.com/0/86330/1170ba25-2e1e-aa41-ff10-7614c7fc9d51.png)


# 実装例
HTML文書を表すクラスを考えてみました。

```html
<html>
  <head>
    <title>hoge</title>
  </head>
</html>
```

HTMLは `<html>`、`<head>` などのタグの中にさらに別のタグ、もしくはテキスト（この場合 `<title>` タグの中の "hoge"）が含まれる、というような再帰的な構造になっているので、タグを Composite 、テキストを Leaf クラスとしています。

## Java での実装

### Component
```java:HtmlElement.java
public abstract class HtmlElement {
  final String INDENT = "  ";

  // depth 分の空白文字を生成します
  protected String indent(int depth) {
    StringBuilder sb = new StringBuilder();
    for (int i=0; i<depth; i++) {
      sb.append(INDENT);
    }
    return sb.toString();
  }

  public abstract void print(int depth);
}
```

`print` を抽象メソッドとして定義し、共通のインターフェースとしています。

### Composite
```java:Tag.java
import java.util.List;
import java.util.ArrayList;
import java.io.PrintStream;

public class Tag extends HtmlElement {
  private String name;
  private List<HtmlElement> children; // 子要素は HtmlElement 型

  public Tag(String name) {
    this.name = name;
    this.children = new ArrayList<HtmlElement>();
  }

  public Tag addChild(HtmlElement child) {
    children.add(child);
    return this;
  }

  // 開始タグ、終了タグで囲んでその間に子要素を出力します
  // このとき子要素が Tag なのか Text なのか を意識しなくて済む、というところがポイント
  @Override
  public void print(int depth) {
    System.out.printf("%s<%s>%n", indent(depth), name);
    for (HtmlElement child : children) {
      child.print(depth + 1);
    }
    System.out.printf("%s</%s>%n", indent(depth), name);
  }
}
```

### Leaf
```java:Text.java
import java.io.PrintStream;

public class Text extends HtmlElement {
  private String text;
  public Text(String text) {
    this.text = text;
  }

  @Override
  public void print(int depth) {
    System.out.println(indent(depth) + text);
  }
}
```

### 呼び出し
```java:Main.java
public class Main {
  public static void main(String[] args) {
    Tag root = new Tag("html");

    Tag head = new Tag("head");
    Tag title = new Tag("title").addChild(new Text("Sample code for Composite Pattern"));
    head.addChild(title);
    root.addChild(head);

    Tag body = new Tag("body");
    Tag h1 = new Tag("h1").addChild(new Text("What is Composite Pattern?"));
    Tag p = new Tag("p")
    .addChild(new Text("In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object. "));

    body.addChild(h1);
    body.addChild(p);
    root.addChild(body);

    root.print(0);
  }
}
```

### 実行結果

```
<html>
  <head>
    <title>
      Sample code for Composite Pattern
    </title>
  </head>
  <body>
    <h1>
      What is Composite Pattern?
    </h1>
    <p>
      In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object.
    </p>
  </body>
</html>
```


## Ruby での実装

### Component
```rb
class HtmlElement
  INDENT = "  ";

  def indent(depth)
    INDENT * depth
  end
end
```
Java で抽象メソッドとしていたメソッドを Component に置くべきか？は悩みどころ。デフォルトの挙動が無ければ不要かもしれません。


### Composite
```rb
class Tag < HtmlElement
  def initialize(name)
    @name = name
    @children = []
  end

  def add_child(child)
    @children << child
    self
  end

  def print(depth=0)
    puts indent(depth) + "<#{@name}>"
    @children.each do |child|
      child.print(depth + 1)
    end
    puts indent(depth) + "</#{@name}>"
  end
end
```


### Leaf
```rb
class Text < HtmlElement
  def initialize(text)
    @text = text
  end

  def print(depth=0)
    puts indent(depth) + @text
  end
end
```

### 呼び出し
```rb
root = Tag.new("html")

head = Tag.new("head")
title = Tag.new("title").add_child(Text.new("Sample code for Composite Pattern"))
head.add_child(title)
root.add_child(head)

body = Tag.new("body")
h1 = Tag.new("h1").add_child(Text.new("What is Composite Pattern?"))
p = Tag.new("p").add_child(Text.new("In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object. "))

body.add_child(h1)
body.add_child(p)
root.add_child(body)

root.print
```

### 実行結果

```
<html>
  <head>
    <title>
      Sample code for Composite Pattern
    </title>
  </head>
  <body>
    <h1>
      What is Composite Pattern?
    </h1>
    <p>
      In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object.
    </p>
  </body>
</html>
```


# 参考
Olsen, R. 2007. [*Design Patterns in Ruby*](https://www.amazon.co.jp/dp/B004YW6M6G/ref=cm_sw_r_tw_dp_JODHxb1S34F51)