Flyweight패턴은 유사한 클래스간의 오버헤드를 피하기 위해 사용되는 패턴이다.때때로 개발자는 데이터를 표현하기 위해 매우 많은 수의 소규모 클래스를 생성해야 한다.만약 해당 인스턴스들이 일부 파라미터를 제외하면,근본적으로는 같은 성질의 것을 결정할 수 있을 경우 개발자는 인스턴스화해야 하느stj로 다른 클래스들의 수를 획기적으로 줄일 수 있게 된다.만약 개발자가 클래스 인스턴스의 외부에 존재하는 이런 변수들(외제적인state들)을 움직여서 해당 변수들을 메소드 호출의 일부분으로 전달할 수 있다면,개발자는 해당 변수들을 공유함으로 써 개별적인 인스턴스들의 수를 획기적으로 줄일 수 있게 된다.
Flyweight패턴은 이런 클래스들을 관리하는 방법을 제공한다.이 패턴은 해당 인스턴스를 독보적인 존재로 만들어주는 인스턴스의 고유한 데이터와 아규먼트로 전달 되는 부수적인 데이터를 참조한다.
구조
역할
v Flyweight의 역할: Flyweight가 외재적인state를 주고 받을 인터페이스를 선언한다.
v Concrete Flyweight:Flyweight인터페이스를 구현하고,필요하다면 내재적인state를 저장할 공간을 추가한다.Concrete Flyweight오브젝트는 공유가 가능해야 한다.직접 저장하고 있는state는 내재적인 것이어야 한다.즉,Concrete Flyweight의 컨텍스트와는 무관한 것이어야 한다.
v Unshared Concrete Flyweight:Flyweight의 모든 서브클래스가 공유가능해야하는 것은 아니다. Flyweight의 인터페이스는 단지 공유를 가능하게 할 뿐이지,강제하는 것은 아니다. Flyweight패턴의 오브젝트 구조에서는Unshared Concrete Flyweight오브젝트가Concrete Flyweight오브젝트를child로써 가지고 있는 것이 일반적이다.
v Flyweight Factory: Flyweight오브젝트를 생성하고 관리한다. Flyweight오브젝트가 적절히 공유됨을 보장한다.클라이언트가flyweight오브젝트를 요구하면,Flyweight Factory가 해당flyweight의 이미 존재하는 오브젝트나 없다면 새것을 만들어서 공급한다.
v Client : Flyweight오브젝트들에 대한reference를 유지한다. Flyweight에 대한 외재적인state를 계산하고 저장한다.
참고사항 Flyweight가 동작하기 위한 근간이 되는state들은 내재적인지 외재적인지 구별되어야 한다.내재적인state는Concrete Flyweight오브젝트 안에 저장되고,내재적인state는 클라이언트 오브젝트가 계산하거나 저장한다.클라이언트는flyweight의operation을 호출 할 때 이 외재적인state를 전달해야 한다. 클라이언트는Concrete Flyweight를 직접적으로 인스턴스화하지 않는다. Flyweight오브젝트들이 적절하게 공유됨을 보장하기 위해서 클라이언트는Flyweight Factory를 통해서만Concrete Flyweight오브젝트를 얻어야 한다. |
의도
많은 수의 작은 오브젝트들을 사용할 때,공유기법을 사용하여 효율성을 높인다.
적용시기
Flyweight패턴의 효율성은 어떻게,어디서 사용되는지와 밀접한 관련이 있다.아래의 모든 조건을 만족하는 경우에만Flyweight패턴을 사용하라.
l 어플리케이션이 많은 수의 오브젝트를 사용한다.
l 급격히 늘어나는 오브젝트의 수 때문에storage비용이 높다.
l 오브젝트state의 대부분을 외재적으로 만들 수 있다.
l 일단 외재적인state만 제거되고 나면 여러 오브젝트의 그룹들을 몇 개의 공유 오브젝트로 대체할 수 있다.
l 어플리케이션의 구현이object identity에 의존하지 않는다. Flyweight오브젝트는 공유될 수 있기 때문에,개념적으로는 구별되어야 할 오브젝트 간에object identity가 같을 수 있다.
결론
Flyweight패턴을 사용하면 외재적인state(특히 이state가 전에는 내재적이었을 경우)를 옮기고,찾아내고,계산하는 데에 소요되는run-time cost가 발생하게 된다.그러나,이러한 비용은 공간 절약에 의해 상쇄되며,이 공간 절약은flyweight가 더 많이 공유될 수록 늘어난다.
공간 절약의 정도는 다음 요인들에 의해 결정된다.
l 공유를 통한 인스턴스 총개수의 감소
l 오브젝트 별 내재적인state의 양
l 외재적인state가 매번 계산되는지 저장되는지의 여부
더 많은flyweight가 공유될 수록 더 많은 공간이 절약되는 것이다.그리고 공유되는state(즉,내재적인state)의 양이 클 수록 많이 절약되는 것이다.오브젝트가 내/외재적인state를 모두 실재적인 양 만큼만 사용하고,외재적인state는 저장되기 보다 매번 새로 계산할 때 공간 절약이 최대가 된다.이렇게 하면 두 가지 측면에서 공간을 절약하는 것이다.공유를 통해 내재적인state를 저장하는 공간을 절약하고,외재적인state를 계산하는 시간이 들어가는 대신에 이를 저장할 공간을 절약하게 된다.
Flyweight패턴은leaf node를 공유하는 그래프와 같은 계층 구조를 표현하기 위해Composite패턴과 자주 결합된다.그러나 공유를 하기 때문에flyweight leaf node는 자신의parent에 대한reference를 유지하기 보다는,외재적인state의 일부로써parent reference가flyweight에 전달된다.
Flyweight패턴을 구현할 때 고려할 사항 l 외재적인state의 제거.외재적인state를 분리해내고 공유할 오브젝트로 부터 이들을 제거하기가 얼마나 쉬운지에 따라Flyweight패턴을 적용할지 말지가 결정된다.만약 공유하기 전의 오브젝트 개수만큼이나 많은 다른 종류의 외재적인state가 존재한다면 이들을 제거하는 것이 공간 비용을 절약하는데에 전혀 도움이 되지 않을 수 있다.이상적으로는 외재적인state는 상대적으로 훨씬 적은 공간만을 차지하는 별도의 오브젝트 구조로 부터 계산될 수 있어야 한다. l 공유 오브젝트 관리하기.오브젝트들이 공유되기 때문에 클라이언트가 그들을 직접적으로 인스턴스화해서는 안 된다. Flyweight Factory가 클라이언트에게 특정flyweight를 지정해 준다. Flyweight오브젝트는 클라이언트가 원하는flyweight오브젝트를 찾을 수 있게하는 집합적인 저장 공간을 사용하는 것이 보통이다 공유 가능이라는 특성은 어떤 형태의reference counting이나garbage collection을 할 수 있음을 의미하기도 한다.그러나, flyweight의 개수가 작은 고정수라면 이런 것들은 필요없다.이런 경우에는 만들어진flyweight를 계속 유지하는 것이 더 유리하다. |
예제소스
|
예제 소스
big-.txt ................ ................ ................ ................ ..##########.... ................ ................ ................ big0.txt ....######...... ..##......##.... ..##......##.... ..##......##.... ..##......##.... ..##......##.... ....######...... ................ big1.txt ......##........ ..######........ ......##........ ......##........ ......##........ ......##........ ..##########.... ................ big2.txt ....######...... ..##......##.... ..........##.... ......####...... ....##.......... ..##............ ..##########.... ................ big3.txt ....######...... ..##......##.... ..........##.... ......####...... ..........##.... ..##......##.... ....######...... ................ big4.txt ........##...... ......####...... ....##..##...... ..##....##...... ..##########.... ........##...... ......######.... ................ big5.txt ..##########.... ..##............ ..##............ ..########...... ..........##.... ..##......##.... ....######...... ................ big6.txt ....######...... ..##......##.... ..##............ ..########...... ..##......##.... ..##......##.... ....######...... ................ big7.txt ..##########.... ..##......##.... ..........##.... ........##...... ......##........ ......##........ ......##........ ................ big8.txt ....######...... ..##......##.... ..##......##.... ....######...... ..##......##.... ..##......##.... ....######...... ................ big9.txt ....######...... ..##......##.... ..##......##.... ....########.... ..........##.... ..##......##.... ....######...... ................ import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class BigChar { private char charname; private String fontdata; public BigChar(char charname) { this.charname = charname; try { BufferedReader reader = new BufferedReader( new FileReader("big" + charname + ".txt") ); String line; StringBuffer buf = new StringBuffer(); while ((line = reader.readLine()) != null) { buf.append(line); buf.append("\n"); } reader.close(); this.fontdata = buf.toString(); } catch (IOException e) { this.fontdata = charname + "?"; } } public void print() { System.out.print(fontdata); } } import java.util.Hashtable; public class BigCharFactory { private Hashtable pool = new Hashtable(); private static BigCharFactory singleton = new BigCharFactory(); private BigCharFactory() { } public static BigCharFactory getInstance() { return singleton; } public synchronized BigChar getBigChar(char charname) { BigChar bc = (BigChar)pool.get("" + charname); if (bc == null) { bc = new BigChar(charname); pool.put("" + charname, bc); } return bc; } } public class BigString { private BigChar[] bigchars; public BigString(String string) { bigchars = new BigChar[string.length()]; BigCharFactory factory = BigCharFactory.getInstance(); for (int i = 0; i < bigchars.length; i++) { bigchars[i] = factory.getBigChar(string.charAt(i)); } } public void print() { for (int i = 0; i < bigchars.length; i++) { bigchars[i].print(); } } } public class mainClass { public static void main(String[] args) { if (args.length == 0) { System.out.println("사용 예: java mainClass 011-9954-1682"); System.exit(0); } BigString bs = new BigString(args[0]); bs.print(); } } |
관련패턴
v Proxy : Flyweight패턴에서는 인스턴스를 생성하는데 시간이 걸리는 경우 인스턴스를 공유해서 처리 스피드를 빠르게 할 수 있습니다. Proxy패턴에서는 대리인을 내세워 처리 스피드를 빠르게 합니다.
v Composite : Flyweight패턴을 사용해서composite패턴의leaf역할을 공유시킬 수 있는 경우가 있다.
v Singleton : FlyweightFactory역할은singleton패턴이 되는 경우가 있다.또한singleton패턴의singleton역할은 하나의 인스턴스만 만들기 때문에 그 인스턴스가 사용되는 모든 곳에서 공유를 하게 됩니다. Singleton역할의 인스턴스는intrinsic한 정보만 가지고 있습니다.
'Programming > Design Pattern' 카테고리의 다른 글
[펌] The Memento Pattern (0) | 2006.01.21 |
---|---|
[펌] The Facade Pattern (0) | 2006.01.21 |
[펌] Chapter 5 Behavioral Patterns(행위 패턴) (0) | 2006.01.21 |
[펌] The Chain of Responsibility Pattern (0) | 2006.01.21 |
[펌] The Command Pattern (0) | 2006.01.21 |