본문 바로가기

Design/Design Pattern

[Design Pattern] Flyweight Pattern

이번 장에서는 플라이웨이트(Flyweight) 패턴에 대해서 알아본다.
샘플 코드는 여기 (링크) 프로젝트의 테스트 코드로 정리해두었다.


플라이웨이트 패턴이란?
위키백과에 따른 정의는 아래와 같다.

동일하거나 유사한 객체들 사이에 가능한 많은 데이터를 서로 공유하여 사용하도록 하여 메모리 사용량을 최소화하는 디자인 패턴이다.
종종 오브젝트의 일부 상태 정보는 공유될 수 있는데, 플라이웨이트 패턴에서는 이와 같은 상태 정보를 외부 자료 구조에 저장하여
플라이웨이트 오브젝트가 잠깐 동안 사용할 수 있도록 전달한다.

결국 무수히 많이 생성되어야하는 객체들(이하 주객체) 간에 공유 가능한 객체(이하 부객체)가 있다면 새로 생성하지 않고 공유하도록 하여
메모리 사용량을 낮추는 디자인 패턴이다.

단, 부객체가 주객체에 의해서 변경되게 되면 다른 주객체 또한 영향을 받으므로 부객체는 변경이 되지 않거나 변경이 되어도 무관한 데이터여야만 한다.

이번에는 회사에 입사 지원한 입사 지원자(주객체)와 입사 지원자의 학교(부객체)를 예로 진행할 예정이다.
주객체는 지원자마다 고유하고 부객체인 지원자의 학교는 지원자들마다 겹칠 수 있는 상황이다.
(학교가 많아지면 코드가 복잡해지므로 전세계에 대학교는 JavaUniversity, KotlinUniversity, PythonUniverty 세 개만 있다고 가정한다.)


GoF Design Patterns에 따르면 아래와 같은 Class Diagram이 그려진다.

Flyweight: Flyweight 객체들의 기능 명세서.

UnsharedConcreteFlyweight: 공유 가능하지 않은 정보를 담을 클래스.

ConcreteFlyweight: 공유 가능한 정보를 담을 클래스.

FlyweightFactory: Flyweight 구현체를 생성할 클래스.

위의 그림을 입사 지원자와 입사 지원자의 학교에 적용하면 아래와 같은 Class Diagram이 그려진다.

Resume(이력서)는 지원자의 고유한 정보(VolunteerInfo)와 공유 가능한 지원자들의 출신 학교 정보(UniversityInfo)를 가지고 있다.
UniversityInfo는 Interface이며 이를 구현한 JavaUniversity, KotlinUniversitInfo, PythonUniversityInfo가 있다.
UniversityInfo는 각각 싱글톤 패턴으로 구현되어 있으며 ResumeFactory를 사용하여 Resume가 생성될 때
필요한 학교 정보를 가져와서(생성이 아닌) 조립하게 된다.


코드를 보면서 하나씩 살펴보도록 한다.

UniversityInfo Interface
학교 정보들이 구현해야하는 메서드가 명시되어 있다.

JavaUniversityInfo, KotlinUniversityInfo, PythonUniversityInfo Class
UniversityInfo의 구현체이며 싱글톤 패턴으로 구현되어 있다. Class Loading 시점에 싱글톤 인스턴스가 생성된다.
학교에 대한 기본 정보인 학교 명, 주소, 설명 등이 있다. (코드의 값들은 무의미한 값이며 객체 생성 매번 발생하면 메모리 사용량이 많다는 것을 보여주기 위한 값이다.)

VolunteerInfo Class
Flyweight 객체에서 공유가 불가능하며 고유한 객체인 지원자 정보 클래스다.

Resume Class
Flyweight 객체로서
객체간 공유 불가능한 지원자 정보(VolunteerInfo)와 객체간 공유 가능한 출신 학교 정보(UniversityInfo)를 가지고 있다.

ResumeFactory Class
FlyweightFactory로서 Resume를 찍어내는 일을 하고 있다.
이 클래스에서의 포인트는 Resume를 생성할 때 새로운 UniversityInfo를 생성하는 것이 아니라 생성되어 있는 싱글톤 인스턴스를
가져와서 Resume를 생성한다는 점이다.

Company Class
지원자 정보(VolunteerInfo)를 생성하고 ResumeFactory를 통해서 Resume를 생성하는 역할을 한다.
Company코드를 통해서 살펴보아야 할 점은 학교의 정보가 변경되었을 때다.
지원자 1 ~ 6은 같은 학교 출신이다. 만약 JavaUniversity의 정보가 변경되었고 모든 이력서의 학교정보가
이력서가 생성될 때마다 생성되어 전부 고유한 값을 가지고 있다면 모든 지원자들의 이력서를 찾아서 변경된 학교 정보를 바꿔주어야했을 것이다.
하지만 우리난 Flyweight, Singletone 패턴을 적용해서 작성하였기 때문에 고유한 인스턴스를 가져와서 정보를 수정해주게 되면
이를 공유하는 모든 객체들에게 반영되게 된다.

아래의 코드는 JavaUniversity의 전화번호가 변경되었을 때 이력서에 포함되어 있는 JavaUniversity의 정보를 수정하는 것이 아니라
Singletone 인스턴스를 가져와서 해당 인스턴스의 전화번호만 수정하는 코드다.

코드를 실행시킨 결과는 아래와 같다.


지금까지 이력서, 지원자의 고유한 정보, 지원자의 출신 학교 정보를 Flyweight 패턴에 적용시켜서 살펴보았다.
이처럼 많이 생성되어야하며, 객체간에 공유해도 되고, 변경사항이 있을 때 모든 객체들에게 반영되기를 바란다면
Flyweight 패턴을 고려해봐야한다.

'Design > Design Pattern' 카테고리의 다른 글

[Design Pattern] Command Pattern  (0) 2022.02.06
[Design Pattern] Iterator Pattern  (0) 2022.02.04
[Design Pattern] Memento Pattern  (0) 2022.02.03
[Design Pattern] State Pattern  (0) 2022.02.03
[Design Pattern] Mediator Pattern  (0) 2022.02.02