개발자로 후회없는 삶 살기

디자인 패턴 PART.플라이웨이트 패턴 본문

[백엔드]/[Java | 학습기록]

디자인 패턴 PART.플라이웨이트 패턴

몽이장쥰 2023. 8. 21. 14:57

서론

※ 이 포스트는 다음 강의의 학습이 목표임을 밝힙니다.

https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard

 

코딩으로 학습하는 GoF의 디자인 패턴 - 인프런 | 강의

디자인 패턴을 알고 있다면 스프링 뿐 아니라 여러 다양한 기술 및 프로그래밍 언어도 보다 쉽게 학습할 수 있습니다. 또한, 보다 유연하고 재사용성이 뛰어난 객체 지향 소프트웨어를 개발할

www.inflearn.com

 

본론

- 패턴 소개

가벼운이라는 뜻으로 복싱 체급중에 가벼운 체급을 플라이 웨이트라고 합니다. 많은 객체를 만드는 어플에서 결국 OOM이 발생할 수 있는데 그때 사용할 수 있는 패턴입니다. 자주 변하지 않는 속성을 따로 모아서 재사용하는 방법입니다.

 

- 코드

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);
}

문자의 속성을 표현한 Character 객체가 있고 val, 색깔, 폰트를 가지고 있습니다. 이 문자 객체를 가지고 편집기에 글을 많이 쓰면 많이 쓸 수록 객체가 많아집니다. 그 만큼 이 객체의 메모리가 최적화되지 않으면 편집기의 성능에 영향을 줄 것입니다. 여기에 플라이웨이트 패턴을 적용합니다.

 

=> 구조

객체의 데이터 중에 자주 변하는 것과 변하지 않는 것을 분리하여 재사용합니다. 변하지 않는 것을 모아 놓은 것이 플라이웨이트고 플라이웨이트를 클라이언트가 팩토리를 통해서 가져다 씁니다. 팩토리에서는 플라이웨이트를 캐싱해서 클라이언트가 가져다 쓸 수 있게끔해서 메모리 사용을 극도로 줄입니다.

 

- 패턴 적용

캐릭터의 속성 중에서 자주 바뀌지 않는 것을 플라이웨이트에 넣습니다. 이건 주관적인 것으로 여기서는 폰트 패밀리와 사이즈라고 보고 이 둘을 묶은 것을 플라이웨이트라고 할 것입니다.

 

-> Font

public final class Font {
    
    final String family;
    
    final int size;
    
    public Font(String family, int size) {
        this.family = family;
        this.size = size;
    }
    
    public String getFamily() {
        return family;
    }
    
    public int getSize() {
        return size;
    }
}

플라이웨이트에 해당하는 폰트 클래스르 만듭니다. 여기에 패밀리와 사이즈를 정의합니다. 이때 주의할 것은 플라이웨이트에 해당하는 속성은 emmutable해야합니다. 따라서 final 키워드를 씁니다. 그리고 상속을 막아야 해서 final 클래스로 만듭니다.

 

public class Character {
    String color;
    private char value;
    Font font;
    
    public Character(String color, char value, Font font) {
        this.color = color;
        this.value = value;
        this.font = font;
    }
}

그리고 변하는 속성을 가지고 있는 캐릭터를 만듭니다. val과 color를 가지고 있고 여기서 Font를 그대로 쓰면 아까와 같은 속성을 캐릭터가 가집니다.

 

-> 플라이웨이트 팩토리

public class FontFactory {
    
    private Map<String, Font> cache = new HashMap<>();
    
    public Font getFont(String font) {
        if (cache.containsKey(font)) {
            return cache.get(font);
        } else {
            String[] split = font.split(":");
            Font newFont = new Font(split[0], Integer.parseInt(split[1]));
            cache.put(font, newFont);
            return newFont;
        }
    }
}

플라이웨이트를 캐싱하고 접근할 수 있어야 합니다. Map으로 캐시를 구현할 것입니다. getFont로 플라이웨이트를 가져오는 메서드를 만듭니다.

 

 

-> 클라이언트

 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"));
}

이제 캐릭터를 만들 때 value, color는 그대로 하는데 폰트는 팩토리에서 가져옵니다. 이렇게 되면 이 폰트 객체들은 모두 공유한 것이라서 메모리를 덜 쓰게 됩니다.


- 장, 단점

어플에서 사용하는 메모리를 줄일 수 있습니다. 기존에는 캐릭터가 모든 데이터를 가지고 있어서 힙에 메모리를 계속 먹을 것인데 플라이웨이트를 하면 하나의 객체를 사용해서 메모리를 아낍니다. 또한 팩토리에서 캐싱을 하기 때문에 항상 동일한 객체를 사용합니다.

Comments