# 플라이웨이트 패턴

## 접근

* 동일한 클래스의 객체를 많이 만들어야 하는 상황에서 성능 상 이점을 취하기 위해 객체 하나로 여러 개의 가상 객체를 제공해야 한다.
* 가상 객체들의 상태를 관리하는 객체를 만들고, 상태를 갖지 않는 객체 하나를 만든다. 객체에 대한 정보를 얻으려면 상태 관리 객체에 요청을 보내야 한다.

## 개념

* 수많은 객체를 생성하여 각각 데이터를 유지하는 대신 여러 객체 간 공통 부분을 공유하여 메모리 용량을 줄일 수 있는 디자인 패턴이다.
* 객체마다 일정하게 유지되는 데이터를 고유한 상태라고 하며, 계속 변화하는 데이터를 공유한 상태라고 한다.
* 고유한 상태는 객체 내부에 저장하여 컨텍스트가 다른 곳에서도 재사용되도록 한다. 이 때 저장되는 객체를 **플라이웨이트**라고 부른다.
* 플라이웨이트 팩토리 클래스는 기존 플라이웨이트 객체를 재사용할지 새로 객체를 만들지 결정한다.
* 공유한 상태는 객체 내부에 저장하지 않고, **컨텍스트** 클래스에 포함해두고 상태에 의존하는 메서드들을 작성해 변화된 상태가 전달되도록 한다. 컨텍스트 클래스에는 고유한 상태인 플라이웨이트도 포함해둔다.

<figure><img src="https://946524419-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZqOTWctN1y9hEXEl4sKd%2Fuploads%2FJOjjQWqDISZOxC5rYEL3%2Fimage.png?alt=media&#x26;token=55d1ff82-6937-4f0e-87eb-22532838239c" alt=""><figcaption></figcaption></figure>



## 장단점

* 장점
  * 실행 시 객체 개수를 줄여 메모리를 절약할 수 있다.
  * 여러 가상 객체의 상태를 한 곳에 모아둘 수 있다.
* 단점
  * 특정 객체만 다르게 행동하도록 구현할 수 없다.

## 사용 방법

* 플라이웨이트를 만들어야 할 만큼 많이 생성되는 클래스의 필드를 고유한 상태와 공유한 상태로 구분한다.
* **고유한 상태**를 나타내는 필드들은 그대로 두고 변경할 수 없도록 한다.
* **공유한 상태**를 사용하는 메서드들을 확인하고, 이 데이터들을 외부로 분리할 것이기 때문에 메서드 매개변수로 받도록 수정한다.
* 필요 시 플라이웨이트 풀을 관리하기 위한 팩토리 클래스를 생성한다.
* 클라이언트는 플라이웨이트 객체들의 메서드들을 호출할 수 있도록 공유한 상태의 값들​(콘텍스트)​을 효율적으로 저장/계산해야 한다.

## 예시

* TreeManager는 여러 Tree 객체의 공유한 상태를 저장하는 Context 클래스이다.

```java
public class TreeManager {
    int[][] treeArr;

    public void displayTrees() {
        for(int i=0;i<treeArr.length;i++) {
            display(treeArr[i][0], treeArr[i][1], age);
        }
    }
}
```

* Tree는 고유한 상태를 저장하는 플라이웨이트 클래스이다.

```java
public class Tree {
    public void display(int x, int y, int age) {
        System.out.println("위치 x: " + x + " y: " + y + " age: " + age);
    }
}
```
