24 Aug 2019

디자인 패턴 11 - 플라이급 (Flyweight)

플라이급(Flyweight) 패턴은 객체 간의 공유를 통해 많은 수의 작은 객체들을 효과적으로 사용하기 위한 패턴이다.

객체 중심으로 설계함으로써 많은 효과를 거둘 때도 많지만, 아주 수많은 인스턴스를 가져야할 경우에는 좀 생각할 문제가 있다. 프로그램 런타임 기간에 많은 인스턴스를 가지는 클래스의 경우에는 객체 인스턴스를 생성하느라 많은 메모리와 긴 실행 시간과 같이 많은 비용이 소모된다. 플라이급 패턴은 이런 문제를 객체 공유를 통해 해결한다.

플라이급 객체는 공유 가능한 객체로, 여러 상황에 대해서 그 객체의 무결성이 깨지지 않도록 객체가 가져야 할 정보를 잘 정의해야 한다. 특히나 상황에 종속적인, 때에 따라 달라지는 값(부가적 상태(extrinsic)은 사용될 수 없다. 예를 들어 문서 편집기에서 글자를 나타내는 객체는 런타임에 수많이 생성될 수 있으므로, 플라이급 패턴을 통해 공유 가능한 객체로 만들 수 있는데 이 때 그 객체가 가져야할 정보는 변하지 않는 값(본질적 상태(intrinsic)), 즉 문자를 나타내는 문자 코드인 것이다. 상황에 따라 달라지는, 문자의 위치나 스타일 등을 나타내는 정보는 플라이급 객체 안에 넣을 수 없다. 그리고 문자를 나타내는 객체를 각 문서마다 이 객체를 공유함으로써 수많은 인스턴스를 가짐으로써 나타나는 비용을 줄일 수 있게 된다.

문자의 위치나 스타일과 같이 플라이급 객체에 넣을 수 없는, 상황에 따라 달라지는 값인 부가적 상태는 매개변수를 통해 플라이급 객체로부터 연산 결과로써 얻어내야 한다.

어떤 상황에서도 변하지 않는, 공유될 수 있는 값인 본질적 상태(Intrinsic)는 플라이급 객체안에 넣고, 상황에 따라 변할 수 있는 부가적인 상태(Extrinsic)는 사용자가 따로 저장하거나, 연산되어 결과 값으로 얻을 수 있는 방식으로 관리되어야 한다.

프로그램 런타임에 수많은 객체 인스턴스를 가지는 클래스가 있을 때, 리팩토링을 통해 상황에 따라 달라지는 값을 분리해내고, 플라이급 패턴으로 서로 공유할 수 있도록 구현하면 많은 효과를 볼 수 있다.

플라이급 객체는 식별성이 있는 도메인, 즉 엔티티(Entity)에서는 사용할 수 없다. 플라이급 객체는 공유가 가능해야 하는데, 식별성이 있다는 의미는 서로 다른 객체로 구별해야 된다는 의미이므로 사용될 수 없다. 상태가 변할 수 없는 불변 객체인 밸류 오브젝트(Value Object)는 플라이급 객체로 만들어볼만 하다.

00.png

위 그림과 같이 클라이언트는 플라이급 객체를 생성하고 관리하는 팩토리 객체로부터 객체 인스턴스를 얻으며, 해당 팩토리는 플라이급 객체들이 서로 공유될 수 있도록 보장한다. UnsharedConcreteFlyweight와 같이 공유할 수 없지만 Flyweight 인터페이스를 상속하는 객체가 있을 수 있다. 모든 플라이급 서브클래스들이 공유될 필요는 없으며, 본질적인 상태가 아닌 상황에 따라 변하는 부가적인 상태를 갖는 클래스라면 공유해서는 안된다.

플라이급 객체를 사용하는 클라이언트는 직접 플라이급 객체 인스턴스를 생성해서는 안되고, 팩토리 객체를 통해 얻어내야 한다.

플라이급 패턴을 통해 공유해야되는 전체 인스턴스의 수를 줄일 수 있으며, 특히 본질적인 상태가 많고 부가적인 상태는 드물게 연산될 때라면 공유의 효과를 크게 볼 수 있다.


Tags:
Stats:
0 comments