관련 영상
플라이웨이트 패턴
- 각 객체에 모든 데이터를 유지하는 대신 여러 객체들 간에 상태의 공통 부분들을 공유하여 사용할 수 있는 RAM에 더 많은 객체들을 포함할 수 있도록 하는 구조 디자인 패턴
- 오브젝트의 일부 상태 정보는 공유될 수 있는데 이를 외부 자료구조에 저장하여 플라이웨이트 오브젝트가 잠깐 동안 사용할 수 있도록 전달.
- 플라이웨이트 패턴은 단지 최적화에 불과
- 이 패턴을 적용하기 전 프로그램이 RAM 소비 문제가 있는지 확인하고, 이 문제가 다른 의미있는 방법으로 해결될 수 없는지도 확인하여라
- 플라이웨이트는 불변해야 한다
- 같은 플라이웨이트 객체가 다른 콘텍스트들에서 사용될 수 있으므로 해당 플라이웨이트 객체의 상태를 수정할 수 없는지 확인해야 한다.
- 플라이웨이트는 생성자 매개변수들을 통해 상태를 한 번만 초기화해야 한다. 또 setter 또는 public 필드들을 다른 객체들에 노출해서는 안 된다다.
- 플라이웨이트 팩토리
- 다양한 플라이웨이트들에 보다 편리하게 액세스하기 위해 기존 플라이웨이트 객체들의 풀을 관리하는 팩토리 메서드를 생성할 수 있다.
- 이 메서드는 클라이언트에서 원하는 플라이웨이트의 고유한 상태를 받아들이고 이 상태와 일치하는 기존 플라이웨이트 객체를 찾고 발견되면 반환한다. 아니면 새 플라이웨이트를 생성해풀에 추가한다.
플라이웨이트 구조
- 플라이웨이트(Flyweight) 클래스
- 여러 객체들간에 공유할 수 있는 원래 객체의 상태의 부분이 포함된다
- 같은 플라이웨이트 객체가 다양한 콘텍스트에서 사용될 수 있다
- 플라이웨이트 내부에 저장된 상태를 고유한(intrinsic) 상태라고 하며, 플라이웨이트 메서드에 전달된 상태를 공유한(extrinsic) 상태라고 한다
- 콘텍스트(Context) 클래스
- 공유한 상태를 포함하며, 이 상태는 모든 원본 객체들에서 고유하다
- 콘텍스트가 플라이웨이트 객체 중 하나와 쌍을 이루면 원래 객체의 전채 상태를 나타낸다
- 클라이언트(Client)
- 플라이웨이트들의 공유된 상태를 저장하거나 계산한다.
- 클라이언트의 관점에서 플라이웨이트는 일부 콘텍스트 데이터를 그의 메서드들의 매개변수들에 전달하여 런타임에 설정될 수 있는 템플릿 객체이다
- 플라이웨이트 팩토리(FlyweightFactory)
- 기존 플라이웨이트들의 풀을 관리
- 클라이언트들은 플라이웨이트들을 직접 만들지 않는 대신 원하는 플라이웨이트의 고유한 상태의 일부를 전달하여 공장을 호출
- 팩토리는 이전에 생성된 플라이웨이트들을 살펴보고 검색 기준과 일치하는 기존 플라이웨이트를 반환하거나 기준에 맞는 플라이웨이트가 발견되지 않으면 새로 생성
플라이웨이트의 적용
- 프로그램이 많은 수의 객체들을 지원해야 해서 사용할 수 있는 RAM을 거의 다 사용했을 때만 사용
- 앱이 수많은 유사 객체들을 생성할 때
- 이것이 대상 장치에서 사용할 수 있는 모든 RAM을 소모할 때
- 이 객체들에 여러 중복 상태들이 포함되어 있으며, 이 상태들이 추출된 후 객체 간에 공유될 수 있을 때 유용하다
다른 패턴과의 관계
- RAM을 절약하기 위하여 복합체 패턴 트리의 공유된 잎 노드들을 플라이웨이트들로 구현할 수 있다.
- 플라이웨이트는 작은 객체들을 많이 만드는 방법을 보여 주는 반면 퍼사드 패턴은 전체 하위 시스템을 나타내는 단일 객체를 만드는 방법을 보여 준다.
- 만약 객체들의 공유된 상태들을 단 하나의 플라이웨이트 객체로 줄일 수 있다면 플라이웨이트는 싱글턴과 유사해질 수 있다. 그러나 이 패턴들에는 두 가지 근본적인 차이점이 있다:
- 싱글턴은 인스턴스가 하나만 있어야 한다. 반면에 플라이웨이트 클래스는 여러 고유한 상태를 가진 여러 인스턴스를 포함할 수 있다.
- 싱글턴 객체는 변할 수 있다 (mutable). 플라이웨이트 객체들은 변할 수 없다 (immutable).
플라이웨이트를 이용한 나무심기
public class Tree {
// 나무는 아래와 같이 3개 정보를 가지고 있습니다.
private String color;
private int x;
private int y;
//색상으로만 생성자를 만들어줄게요.
public Tree(String color) {
this.color = color;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
//나무를 심을 때
public void install(){
System.out.println("x:"+x+" y:"+y+" 위치에 "+color+"색 나무를 설치했습니다!");
}
}
public class TreeFactory {
//HashMap 자료구조를 활용해서 만들어진 나무들을 관리해볼게요
public static final HashMap<String, Tree> treeMap = new HashMap<>();
public static Tree getTree(String treeColor){
//Map에 입력받은 색상의 나무가 있는지 찾습니다. 있으면 그 객체를 제공합니다.
Tree tree = (Tree)treeMap.get(treeColor);
//만약 아직 같은 색상의 나무가 Map에 없다면 새로 객체를 생성해 제공합니다.
if(tree == null){
tree = new Tree(treeColor);
treeMap.put(treeColor, tree);
System.out.println("새 객체 생성");
}
return tree;
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("원하는 색을 입력해주세요 :)");
for(int i=0;i<10;i++){
//나무 색 입력받기
String input = scanner.nextLine();
//팩토리에서 나무 하나 공급받기
Tree tree = (Tree)TreeFactory.getTree(input);
//나무 x,y 설정하고
tree.setX((int) (Math.random()*100));
tree.setY((int) (Math.random()*100));
//나무 설치하기
tree.install();
}
}
}