(인프런) 코딩으로 학습하는 GoF의 디자인 패턴 - 백기선, 강의를 보고 정리한 글입니다.
코드는 GitHub 에 있습니다
#1. 객체 생성 관련 패턴 |
#2. 구조 관련 패턴 |
#3. 행동 관련 패턴 |
||
✔️ 플라이웨이트 패턴 이란 (Flyweight Patterns)
flyweight 는 가볍다는 뜻을 가지고 있습니다.
- 플라이웨이트 패턴은, 객체를 가볍게 만들어 메모리 사용을 줄인다는 목적을 가지는 패턴입니다.
- 플라이웨이트 패턴은, 자주 변하는 속성과 변하지 않는 속성을 분리하고 재사용하여 메모리 사용을 줄이는 구조를 설계하는 패턴입니다.
- 주로 굉장히 많은 인스턴스를 가지고 있는 어플리케이션에 사용되는 패턴입니다.
- 인스턴스가 많으면 메모리를 많이 잡게되고 OOM 즉, Out Of Memory 문제가 발생할 수 있기에 이를 예방하기 위한 패턴입니다.
→ 요점은 메모리를 줄이는 것인데, 주로 캐싱을 사용합니다.
✔️ 플라이웨이트 패턴 예시
- 플라이웨이트에서 중요한것은 변하지 않는 속성을 분리하는 것. 입니다.
- 아래 처럼 Character 라는 객체에, font 의 종류와 사이즈가 똑같은게 종종 사용된다고 느껴져 미리 만들어 (캐싱) 메모리를 아끼고 싶다!
- 는 생각이 든다면 플라이웨이트 패턴을 적용하기 좋은 상태입니다.
public class Client {
public static void main(String[] args) {
Character c1 = new Character('h', "white", "Nanum", 12);
Character c2 = new Character('e', "white", "Nanum", 12);
Character c3 = new Character('l', "white", "Nanum", 12);
Character c4 = new Character('l', "white", "Nanum", 12);
Character c5 = new Character('o', "white", "Nanum", 12);
}
}
public class Character {
private char value;
private String color;
private String fontFamily;
private int fontSize;
public Character(char value, String color, String fontFamily, int fontSize) {
this.value = value;
this.color = color;
this.fontFamily = fontFamily;
this.fontSize = fontSize;
}
}
↓
플라이웨이트 패턴 적용
- 아래처럼 우선 Font 에 대한 정보를 객체로 추출했습니다.
- 이제 중요한 것은 캐싱이겠죠
//자주 바뀌는 객체와 안바뀌는 객체를 판단하는게 중요함
public class Character {
private char value;
private String color;
private Font font;
public Character(char value, String color, Font font) {
this.value = value;
this.color = color;
this.font = font;
}
}
/**
* flyweight 객체
* flyweight 객체는 불변한 객체이야 한다. → 변하지 않는 객체로 판단해서 flyweight 객체로 빼서 모든 곳에서 공유하기 때문에 불변해야함
*/
public final class Font {
private final String family;
private final int size;
public Font(String family, int size) {
this.family = family;
this.size = size;
}
}
플라이웨이트 캐싱 - 팩토리
- 팩토리라 이야기하지만, 캐싱의 방법이야 저는 어떻게 구현하든 상관없다는 생각이 들었습니다.
- 강의 예제에서는, 마치 데이터베이스인 것 처럼 Map 을 이용하여 우선 사용하고자 하는 폰트가 Map 에 존재하면 꺼내서 같은 객체를 추출하고,
- 없다면 생성해 Map 에 저장후 생성한 객체를 반환해 주었습니다.
/**
* flyweight factory
*
* flyweight 갹체를 캐싱해서 가져오는 역할
*/
public class FontFactory {
Map<String, Font> cache = new HashMap<>();
public Font getFont(String font) {
if (cache.containsKey(font)) {
return cache.get(font);
}
String split[] = font.split(":");
Font newFont = new Font(split[0], Integer.parseInt(split[1]));
cache.put(font, newFont);
return newFont;
}
}
플라이웨이트 캐싱 - 클라이언트
- 이렇게 된다면 클라이언트에서 Font 는 항상 캐싱처리를 하고있는 FontFactory를 통해 불러오고
- 아래의 예시에서는 나눔 - 12 size 의 font 를 처음 호출할때만 생성하고 이후에는 계속 같은 객체를 반환해서 메모리를 아낄 수 있겠죠
public class Client {
public static void main(String[] args) {
FontFactory fontFactory = new FontFactory();
Character c1 = new Character('h', "white", fontFactory.getFont("nanum:12"));
Character c2 = new Character('e', "white", fontFactory.getFont("nanum:12"));
Character c3 = new Character('l', "white", fontFactory.getFont("nanum:12"));
}
}
📌 플라이웨이트 주의할 점
- 위에서 의아한함을 느꼈을 수 도 있지만, 캐싱 후 같은 객체를 넘겨주기 때문에 이 Flyweight 로 추출한 객체는 불변해야합니다.
- 불변 객체가 아니라면, 어디서 어떻게 데이터가 변경이 일어나는지 도저히 알 수 없고 참조하고 있는 모든 부분에서의 데이터가 어그러지기 때문입니다.
- 위에서 Font 객체를 final 로 정의한 이유입니다.
public final class Font {
private final String family;
private final int size;
public Font(String family, int size) {
this.family = family;
this.size = size;
}
}
✔️ JAVA 에서의 플라이웨이트 예시
1) Java Integer -valueOf
- JAVA Integer 참조 객체에서 valueOf 메소드에서 캐싱을 사용하고 있습니다.
- 일종의 플라이웨트 패턴이죠
📌 따라서 캐싱이 되어있는 128까지의 정수는 호출시 같은 객체를 반환해 == 연산에 같은 주소를 반환하는 같은 레퍼런스이기 때문에 true 지만 129부터는 false 가 됩니다.
//true
@Test
void test() {
Integer a = Integer.valueOf(100);
Integer b = Integer.valueOf(100);
System.out.println("a = b " + (a == b)) ;
}
//false
@Test
void test() {
Integer a = Integer.valueOf(129);
Integer b = Integer.valueOf(129);
System.out.println("a = b " + (a == b)) ;
}
2) String Context Pool
다른 언어에서는 모르겠지만, Java의 String 은 다른 Reference Type 들과 다르게 Context Pool 을 이용하는 독특한 특징을 가집니다.
이상 플라이웨이트 패턴 끝입니다!
'Java > Design Pattern' 카테고리의 다른 글
[디자인 패턴] 행동 패턴 - 커맨드 패턴 (Command Pattern) (0) | 2023.03.29 |
---|---|
[디자인 패턴] 구조 패턴 - 프록시 패턴 (Proxy Pattern) (0) | 2023.03.24 |
[디자인 패턴] 구조 패턴 - 퍼사드 패턴 (Facade Pattern) (0) | 2023.03.09 |
[디자인 패턴] 구조 패턴 - 데코레이터 패턴 (Decorator Pattern) (0) | 2023.03.07 |
[디자인 패턴] 구조 패턴 - 컴포지트 패턴 (Composite Patterns) (0) | 2023.03.01 |