Compositeパターン

# はじめに
GoFデザインパターンの一つで,構造に関するパターンである
**Compositeパターン**について扱いたいと思います.

# Compositeパターンとは?
Compositeパターンとは,**オブジェクトを階層構造で表現し、個々のオブジェクトとそのグループを同一視できるようにするデザインパターン**です.

...つまり,どういったことができるようになるのでしょう？？？

ポイントは**同一視**というワードです.
   
同一視することができるというのは,
**階層構造のものに一つのインタフェースを実装することで,
違うクラスであっても同じオブジェクトとして扱うことが可能になる**ということです.

...言葉ではよくわからないので例を見ていきましょう.

# Compositeパターンの実装
図形を例にした時の,Compositeパターンの構造は以下のようになります.

CompositeShapeがShapeのインスタンスのリストを管理します.

そして,CompsiteShapeのdraw()が呼び出されると,リストに登録されているShapeのインスタンスにメソッドの処理を委譲します.

つまり,CompsiteShapeを一つのShapeと見なすことができ,CompositeShapeだけで様々な図形を描くことができます.

これは,CompositeShapeとShapeを**同一視することができる**というのを表しています.
![スクリーンショット 2025-01-03 040039.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3586226/3b44cdfb-0d11-90c6-2456-3ab74c6aeb43.png)

以下は具体的なソースコードと実装例になります.

- App.java

```App.java
public class App {
    public static void main(String[] args) {
        
        Shape circle = new Circle();
        Shape square = new Square();
        
        CompositeShape compositeShape = new CompositeShape();
        compositeShape.add(circle);
        compositeShape.add(square);
        
        CompositeShape nestedComposite = new CompositeShape();
        nestedComposite.add(compositeShape);
        nestedComposite.add(new Circle());

        System.out.println("Drawing individual shapes:");
        circle.draw();
        square.draw();

        System.out.println("\nDrawing composite shape:");
        compositeShape.draw();

        System.out.println("\nDrawing nested composite shape:");
        nestedComposite.draw();
    }
}
```

- Shape.java

```java:Shape.java
interface Shape {
    void draw();
}
```

- Circle.java

```java:Circle.java
class Circle implements Shape{
    @Override
    public void draw() {
        System.out.println("Drawing a Circle");
    }
}
```

- Square.java

```java:Square.java
class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a Square");
    }
}
```

- CompositeShape.java

```java:CompositeShape.java
import java.util.ArrayList;
import java.util.List;

class CompositeShape implements Shape {
    private List<Shape> shapes = new ArrayList<>();

    public void add(Shape shape) {
        shapes.add(shape);
    }

    public void remove(Shape shape) {
        shapes.remove(shape);
    }

    @Override
    public void draw() {
        System.out.println("Drawing a CompositeShape with the following shapes:");
        for (Shape shape : shapes) {
            shape.draw();
        }
    }
}
```

```:実装例
Drawing individual shapes:
Drawing a Circle
Drawing a Square

Drawing composite shape:
Drawing a CompositeShape with the following shapes:
Drawing a Circle
Drawing a Square

Drawing nested composite shape:
Drawing a CompositeShape with the following shapes:
Drawing a CompositeShape with the following shapes:
Drawing a Circle
Drawing a Square
Drawing a Circle
```

# で、何が嬉しいの？
同一視することができるといいましたが,
どういったことがメリットとして挙げられるのでしょうか？

それは,1対多の関係を1対1の関係で表せるので,コードがシンプルになることが考えられるでしょう.

リストを管理するコードや繰り返しのためのコードをCompositeクラスの中に一度だけ記述するだけで済むためです.

# 使うべき場面
Compositeパターンを使うべき場面として考えられるのは,
すべてのオブジェクトが全く等価で取り扱われる場合が考えられます.

そのため,1対多の関係を見つけたときに,あるクラスがどのオブジェクトも等価で取り扱っていたならば,Compositeパターンの導入を考えてみてもいいのではないでしょうか.

# 参考
https://tamotech.blog/2024/05/03/composite/