ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 플라이웨이트 패턴 (Flyweight Pattern)
    디자인 패턴 2022. 7. 22. 21:18

    플라이웨이트 패턴 (Flyweight Pattern)


    • 객체를 가볍게 만들어 메모리 사용을 줄이는 패턴
    • 자주 변화는 속성과 변하지 않는 속성을 분리하고 변하지 않는 속성을 캐시하여 재사용해 메모리 사용을 줄일 수 있다.

     

     

     

    플라이웨이트 패턴 적용 전


    편집기를 만든다 가정하고 글자들을 관리하기 위해 Character 클래스를 만들었다.

    public class Character {
      char value;
      String color;
      int fontSize;
      String fontFamily;
    
      public Character(char value, String color,String fontFamily, int fontSize) {
        this.value = value;
        this.color = color;
        this.fontSize = fontSize;
        this.fontFamily = fontFamily;
      }
    }
    

     

    글자 하나마다 value, color, fontFaily, fontSize 가 부여된다.

    이를 사용하는 Client 는 아래와 같을 것이다.

    public class Client {
      public static void main(String[] args) {
        Character character = new Character('h', "white", "Nanum", 12);
        Character character2 = new Character('e', "white", "Nanum", 12);
        Character character3 = new Character('l', "white", "Nanum", 12);
        Character character4 = new Character('l', "white", "Nanum", 12);
        Character character5 = new Character('o', "white", "Nanum", 12);
      }
    }

     

    여기서 문제점이 보인다.

    Client 코드를 보면 value 만 다른 Character 객체를 계속해서 만들고 있다.

    이 때 Character 객체를 계속해서 만들어 여러가지 속성(필드) 값을 가지고 있어야 하는데 이는 메모리 낭비가 심하다.

     

    이를 플라이웨이트 패턴으로 해결 할 수 있다.

     

     

     

    플라이웨이트 패턴 적용 후


    Character 클래스에서 어떤 부분을 자주 변하는 부분(extrinsit) 으로 보고, 어떤 부분을 자주 변하지 않는 부분(intrinsit)으로 볼 지 정해야한다. 여기서는 value, color 를 자주 변하는 부분으로 보고, fontFamily 와 fontSize 는 자주 변하지 않는 부분으로 정해보자. 

     

    자주 변하지 않는 부분으로 정한 필드들은 따로 Font 클래스를 분리해야 한다. 

     

    [참고]

    intrinsit 해당 객체가 flyweight 객체이다. 

    Immutable 한 클래스여서 한번 생성하면 수정 할 수 없다.

     

    이러한 이유 때문에 final 클래스로 설정하였고, 필드도 final 키워드를 설정하였다.

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

     

     

    생성된 Font 들을 관리하는 FontFactory 는 아래와 같다.

    정확히는 Flyweight 인스턴스에 접근하고, 캐싱하는 역할을 한다.

     

    해당 클래스는 이미 생성된 Font 라면 그대로 반환하고, 새로운 Font 이면 새로 생성하여 저장한다.

    import java.util.HashMap;
    import java.util.Map;
    
    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;
        }
      }
    }

     

     

    이제 자주 변하는 부분인 Character 를 구현해보자.

    해당 클래스는 fontFamily 와 fontSize 를 Font 클래스로 가지고 있다.

    public class Client {
      public static void main(String[] args) {
        // font 객체를 관리하는 fontFactory
        FontFactory fontFactory = new FontFactory();
    
        Character character = new Character('h', "white", fontFactory.getFont("nanum:12"));
        Character character2 = new Character('e', "white", fontFactory.getFont("nanum:12"));
        Character character3 = new Character('l', "white", fontFactory.getFont("nanum:12"));
        Character character4 = new Character('l', "white", fontFactory.getFont("nanum:12"));
        Character character5 = new Character('o', "white", fontFactory.getFont("nanum:12"));
      }
    }

    fontFactory.getFont("nanum:12") 를 통해 font 객체를 가져오면  모두 같은 font 객체를 받을 것이고, 객체의 생성을 가볍게 만들 수 있어 메모리 낭비를 줄일 수 있다.

     

    Font 객체를 HashMap 으로 캐싱하여 조회속도 O(1) 이점을 얻을 수 있고, Character 객체는 생성될 때 마다 무거운 필드값을 모두 새로 설정하지 않아도 된다.

     

     

    정리

    1. 특정 클래스에서 자주 사용되는 필드와 자주 사용되지 않는 필드를 분리하였고, 자주 사용되는 필드의 경우 따로 클래스를 만들었다.

    2. 자주 사용되는 필드들을 가지고 있는 클래스(이하 Flyweight) 는 Immutable 하게 설정하였다.

    3. 해당 클래스를 관리하는 FlyweightFactory 클래스를 만들어 Flyweight 객체를 캐싱 처리한다.    

    (이미 생성된 Flyweight 라면 그대로 반환되도록 구현하였다.)

     

     

     

    장점과 단점


    장점

    • 애플리케이션에서 사용하는 메모리를 줄일 수 있다.

    단점

    • 코드의 복잡도가 증가한다.

     

     

     

    참고


     

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

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

    www.inflearn.com

     

Designed by Tistory.