ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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 객체는 싱글톤 객체로 구현한다.






    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class 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마다 단 하나의 객체만 생성되도록 보장







     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    enum 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.java
    1
    2
    3
    4
    5
    6
    7
    8
     
    package flyweight;
     
    public interface ICoffee {
        public void serveCoffee(CoffeeContext context);
    }
     
     
    cs

     




    Coffee.java

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    package 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    package flyweight;
     
    public class CoffeeContext {
        private final int tableNumber;
     
        public CoffeeContext(int tableNumber) {
            this.tableNumber = tableNumber;
        }
     
        public int getTable() {
            return this.tableNumber;
        }
    }
     
    cs




    CoffeeFactory.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    package 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    package 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







    댓글

Designed by Tistory.