Lee's Grow up

[디자인패턴/Design Pattern] Flyweight Pattern / 플라이웨이트 패턴 본문

PROGRAMMING/디자인패턴

[디자인패턴/Design Pattern] Flyweight Pattern / 플라이웨이트 패턴

효기로그 2019. 12. 31. 14:31
반응형

관련 내용은 [자바 언어로 배우는 디자인 패턴 입문],[Head First Design Pattern]의 내용을 참고해서 정리한 글입니다.
잘못된 부분은 댓글로 피드백 부탁드립니다.

1. Flyweight 패턴이란?


어떤 클래스의 인스턴스 한 개만 가지고 여러 개의 "가상 인스턴스"를 제공하고 싶을 때 사용하는 패턴입니다.
즉 인스턴스를 가능한 대로 공유시켜 쓸데없이 new연산자를 통한 메모리 낭비를 줄이는 방식입니다.

2. Flyweight 패턴의 등장인물


  • Flyweight(플라이급)의 역할
    1. 공유에 사용할 클래스들의 인터페이스(API)를 선언합니다.
  • ConcreteFlyweight(구체적인 플라이급)의 역할
    1. Flyweight의 내용을 정의합니다. 실제 공유될 객체입니다.
  • FlyweightFactory(플라이급의 공장)의 역할
    1. 해당 공장을 사용해서 Flyweight의 인스턴스를 생성 또는 공유해주는 역할을 합니다.
  • Client(클라이언트)의 역할
    1. 해당 패턴의 사용자 입니다.
Flyweight 패턴의 클래스 다이어그램

3. 예제


3-1. Shape 인터페이스
public interface Shape {
    public void draw();
}

해당 패턴을 적용할(공유로 사용될) 클래스들의 인터페이스(API)를 작성합니다.

3-2. Circle 클래스
public class Circle implements Shape {
    private String color;
    private int x;
    private int y;
    private int radius;

    public Circle(String color) {
        this.color = color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("Circle [color=" + color + ", x=" + x + ", y=" + y + ", radius=" + radius + "]");
    }
}

ConcreteFlyweight에 해당하며 인터페이스(API)의 내용을 정의하고, 필요한 속성을 가질 수 있습니다.

3-3. ShapeFactory 클래스
public class ShapeFactory {
    private static final HashMap<String, Circle> circleMap = new HashMap<>();

    public static Shape getCircle(String color) {
        Circle circle = (Circle)circleMap.get(color);

        if(circle == null) {
            circle = new Circle(color);
            circleMap.put(color,circle);
            System.out.println("==== 새로운 객체 생성 : " + color + "색 원 ====" );
        } 

        return circle;
    }
}

getCircle()메소드를 통해 객체의 생성 또는 공유의 역할을 담당하며 클라이언트에게 응답해줍니다.

3-4. Main 클래스
public class Main {
    public static void main(String[] args) {
        String[] colors = {"Red","Green","Blue","Yellow"};

        for (int i = 0; i < 10; i++) {
            Circle circle = (Circle)ShapeFactory.getCircle(colors[(int) (Math.random()*4)]);
            circle.setX((int) (Math.random()*100));
            circle.setY((int) (Math.random()*4));
            circle.setRadius((int) (Math.random()*10));
            circle.draw();
        }
    }
}
실행 결과
==== 새로운 객체 생성 : Yellow색 원 ====
Circle [color=Yellow, x=76, y=2, radius=4]
Circle [color=Yellow, x=19, y=2, radius=8]
==== 새로운 객체 생성 : Red색 원 ====
Circle [color=Red, x=38, y=2, radius=2]
Circle [color=Red, x=41, y=0, radius=1]
Circle [color=Yellow, x=58, y=3, radius=2]
Circle [color=Yellow, x=31, y=0, radius=6]
==== 새로운 객체 생성 : Blue색 원 ====
Circle [color=Blue, x=7, y=3, radius=7]
Circle [color=Blue, x=84, y=2, radius=1]
Circle [color=Yellow, x=90, y=2, radius=2]
==== 새로운 객체 생성 : Green색 원 ====
Circle [color=Green, x=34, y=0, radius=2]

로직에 의해 같은 색상의 원은 1개만 생성되며 생성된 객체를 공유하는걸 확인할 수 있습니다.

그렇다면 왜 사용할까?
  • 실행시에 객체 인스턴스의 개수를 줄여서 메모리를 절약할 수 있습니다,
  • 여러 "가상" 객체의 상태를 한 곳에 집중시켜놓을 수 있습니다.

즉 어떤 클래스의 인스턴스가 아주 많이 필요하지만 모두 똑같은 방식으로 제어할 수 있는 경우에 유용하게 사용됩니다,
그러나 아래와 같은 단점이 존재합니다.

  • 특정 인스턴스만 다른 인스턴스처럼 동작하도록 하는 것이 불가능
  • 객체의 값을 변경하면 공유받은 "가상" 객체를 사용하는 곳에 영향을 줄 수 있습니다.

4. 관련 패턴


  • Proxy 패턴 : Flyweight 패턴에서는 인스턴스의 생성에 시간이 걸리는 경우, 인스턴스의 공유에 따라서 처리 속도가 향상됩니다. link
  • Composite 패턴 : Flyweight 패턴을 사용해서 Composite 패턴의 Leaf 역할을 공유시킬 수 있는 경우가 있습니다. link
  • Singleton 패턴 : FlyweightFactory를 Singleton으로 구현하는 경우가 있습니다. link
반응형
Comments