-
[Design Pattern] 플라이웨이트(Flyweight) 패턴 - 디자인 패턴CSE/Design Pattern 2015. 6. 13. 10:40
Pattern #12 플라이웨이트 패턴
본질적인 것과 부가적인 것을 구분하려 할 때 사용
패턴 요약
- 수많은 작은 객체를 생성하여야 할 때
- 사용되는 많은 객체의 생성 관리하는 객체를 따로 두어 이를 통해 필요한 객체를 참조형태로 사용하도록
동기
당신에게 새로 주어진 일은 ‘실시간 전략 시뮬레이션 게임’ 을 개발하는 일이다. 평소에 게이머로서 Starcraft 게임의 재미에 푹 빠져있던 당신은 개발자로써 다시 한번 그 게임에 대하여 놀라게 된다. "아니 어떻게 수 백 개 이상이 되는 많은 캐릭터들이 성능이 뒤떨어진
컴퓨터에서도 무리 없이 병렬적으로 동작을 하는가? 어떻게 설계되었을까?" 당신이 만드는 전략게임에는 ‘병사’, ‘전차’, ‘비행기’ 등이 동시에 수 천 개까지 표현될 수 있어야 한다. "어떻게 설계해야 될까?"
객체 분석
- sizeof(Character): 4kbyte; 이미지 포함
- 1000개의 캐릭터에 필요한 메모리: 4 Mega
- 각 객체가 가지는 정보들 중에서 Character 별로 공유될 수 있는 정보들이 있음
Character Share
- 캐릭터 객체의 모든 정보를 공유할 순 없지만, 공유할 수 있는 정보를 외부 객체로 만들고 이를 공유
- 화면에 나오는 1000개의 캐릭터에 필요한 객체들
* 1000개의 Character subclass(Solider, Tank, Plane) 객체들
* 3개의 CharacterShare subclass (SoliderShare, TankShare, PlaneShare) 객체들
* 1000 * 12bytes + 3 * 4000bytes = 24000bytes
공유를 위한 Class diagram
공유객체 관리 해결방안 1: 싱글톤 패턴 사용하기
- 각 캐릭터 객체(aSolider, aTank, aPlane)는 자신에게 맞는 CharacterShare 객체(aSoliderShare, aTankShare, aPlaneShare)를 생성한다.
- 각 CharacterShare 객체는 싱글톤 객체로 구현한다.
12345678910111213class CharacterShare{...CharacterShare *pInstance;}static CharacterShare *SoliderShare::createInstance(){if (pInstance == NULL)pInstance = new SoliderShare();return pInstance;}cs 공유객체 관리 해결방안 1: 팩토리 사용하기
- CharacterShare subclass 객체를 생성하는 Factory class 작성
- 각 캐릭터 객체(aSolider, aTank, aPlane)는 자신에게 맞는 CharacterShare 객체 생성을 Factory에게 요청한다.
- Factory는 각 CharacterShare subclass마다 단 하나의 객체만 생성되도록 보장
12345678910111213141516171819enum CharacterType { SOLIDER = 0, TANK, PLANE};class ShareFactory{CharacterShare *getShare(CharacterType ctype);...private:CharacterShare *shares[3];};CharacterShare *ShareFactory::getShare(CharacterType ctype){if (shares[ctype] == NULL)shares[ctype] = (ctype = 0) ? new SoliderShare :(ctype = 1) ? new TankShare:(ctype = 2) ? new PlaneShare;return shares[ctype];}cs 의도
- 수많은 작은 객체들을 효과적으로 설계하기 위해 객체를 공유하기
적용범위
- 응용 프로그램이 많은 객체를 필요로 할 때
- 많은 객체의 사용으로 저장 공간에 대한 부담이 클 때
- Extrinsic state를 제외하면, 대부분의 객체들이 상대적으로 소수의 공유 객체로 대체될 수 있을 때
- 으용 프로그램이 객체들을 서로 구분할 필요가 없을 때
예제.ICoffee.java12345678package flyweight;public interface ICoffee {public void serveCoffee(CoffeeContext context);}cs Coffee.java
1234567891011121314151617181920212223package flyweight;public class Coffee implements ICoffee {private final String flavor;public Coffee(String newFlavor) {this.flavor = newFlavor;System.out.println("Coffee is created! - " + flavor);}public String getFlavor() {return this.flavor;}public void serveCoffee(CoffeeContext context) {System.out.println("Serving " + flavor + " to table "+ context.getTable());}}cs CoffeeContext.java
123456789101112131415package flyweight;public class CoffeeContext {private final int tableNumber;public CoffeeContext(int tableNumber) {this.tableNumber = tableNumber;}public int getTable() {return this.tableNumber;}}cs CoffeeFactory.java
123456789101112131415161718192021222324package flyweight;import java.util.HashMap;public class CoffeeFactory {private HashMap<String, Coffee> flavors = new HashMap<String, Coffee>();public Coffee getCoffeeFlavor(String flavorName) {Coffee flavor = flavors.get(flavorName);if (flavor == null) {flavor = new Coffee(flavorName);flavors.put(flavorName, flavor);}return flavor;}public int getTotalCoffeeFlavorsMade() {return flavors.size();}}cs FlyweightMain.java
1234567891011121314151617181920212223242526272829303132333435363738package flyweight;public class FlyweightMain {private static Coffee[] coffees = new Coffee[20];private static CoffeeContext[] tables = new CoffeeContext[20];private static int ordersCount = 0;private static CoffeeFactory coffeeFactory;public static void takeOrder(String flavorIn, int table) {coffees[ordersCount] = coffeeFactory.getCoffeeFlavor(flavorIn);tables[ordersCount] = new CoffeeContext(table);ordersCount++;}public static void main(String args[]) {coffeeFactory = new CoffeeFactory();takeOrder("Cappuccino", 2);takeOrder("Cappuccino", 2);takeOrder("Regular Coffee", 1);takeOrder("Regular Coffee", 2);takeOrder("Regular Coffee", 3);takeOrder("Regular Coffee", 4);takeOrder("Cappuccino", 4);takeOrder("Cappuccino", 5);takeOrder("Regular Coffee", 3);takeOrder("Cappuccino", 3);for (int i = 0; i < ordersCount; i++) {coffees[i].serveCoffee(tables[i]);}System.out.println("\n Total Coffee objects made: "+ coffeeFactory.getTotalCoffeeFlavorsMade());}}cs 'CSE > Design Pattern' 카테고리의 다른 글
[Design Pattern] 중재자(Mediator) 패턴 - 디자인 패턴 (0) 2015.06.13 [Design Pattern] 반복자(Iterator) 패턴 - 디자인 패턴 (0) 2015.06.13 [Design Pattern] 인터프리터(Interpreter) 패턴 - 디자인 패턴 (0) 2015.06.13 [Design Pattern] 브릿지(Bridge) 패턴 - 디자인 패턴 (0) 2015.06.13 [Design Pattern] 프록시(Proxy) 패턴 (0) 2015.06.13 [Design Pattern] 어뎁터(Adapter) 패턴 - 디자인 패턴 (0) 2015.06.13