2016년 6월 20일 월요일

flyweight 패턴

■ 정의

[GOF]
 - 공유를 통한 많은 수의 소립 객체들을 효과적으로 지원

[ 실용주의 디자인패턴 ]
- 메모리 사용량을 줄이기 위해 외부 상태(상태정보 저장, 계산)를 사용하거나
  공유(객체의 복사본 대신 단일 객체에 대한 다중 참조를 이용)한다.
- 무엇을 하느냐에 의해 정의, 즉 메소드에 의해 정의됨

▶ 즉 공유하는 객체를 이용하되 상태 정보를 외부 객체가 따로 관리



■ 사용 예
- game of life를 단순하게 구현할때 '셀'이 살아있는가?는 주변 상태를 참조를 지니고 있어야된다. 1024*1024를 표현하려해도 40mb가 필요함
flywieght를 사용하면 동일한 상태를 지닌 객체가 단 하나의 객체를 통해 표현



■ 장/단점
- 장점 : flyweight를 사용하지 않으면 객체지향적으로 구현하기가 힘듬
- 장점 : flyweight 풀을 이용하면 자바의 == 연산자로 객체의동일성 여부를 결정 할 수 있다.

- 단점 : 외부상태가 계산되는 값이라면(매번 데이터베이스에 접근) 하면 접근이 느릴 수 있다.
- 단점 : 코드가 복잡해짐, 유지보수를 어렵게하고 코드가 커질 수 있음


■ 코드 예제
쉬운 예>
ElementStyle e = new ElementStyle;
e.setMargin(ElementStyleFactory.createMargin(10,10,20,10)); -> 객체는 공유하되 외부 객체가 따로 관리 되도록

게임프로그래밍 패턴예제(js로 구현)>
[origin]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>flyweight origin</title>
</head>
<body>
경량패턴??<br>
어떤 객체의 수가 너무 많아 좀 가볍게 만들고 싶을때 사용<br>
고유상태와 외부상태로 나눔<br>
<br>
예제 : 지형 만들기<br>
타일(고유상태)과 각 타일들이 갖고 있는 정보(외부상태)<br>
<script>
    function Terrain(kind){
        return {
            "TERRAIN_CLASS" : "TERRAIN_CLASS",
            "TERRAIN_HILL" : "TERRAIN_HILL",
            "TERRAIN_RIVER" : "TERRAIN_RIVER"        }[kind];
    }

    function World(){
        this.tiles = {};
    }
    World.prototype.getMovementCost = function(x,y){
        return {
            "TERRAIN_CLASS" : 1,
            "TERRAIN_HILL" : 2,
            "TERRAIN_RIVER" : 3        }[this.tiles[x][y]];
    };

    World.prototype.getIsWater = function(x,y){
        return {
            "TERRAIN_CLASS" : false,
            "TERRAIN_HILL" : false,
            "TERRAIN_RIVER" : true        }[this.tiles[x][y]];
    };

    World.prototype.setTile = function(x,y, value){
        this.tiles = this.tiles||{};

        this.tiles[x] = this.tiles[x]||{};
        this.tiles[x][y] = this.tiles[x][y]||"";
        this.tiles[x][y] = value;

    };


    function Main(){
        var world = new World;
        var terrain_class = Terrain("TERRAIN_CLASS");
        var terrain_hill = Terrain("TERRAIN_HILL");
        var terrain_river = Terrain("TERRAIN_RIVER");

        world.setTile(1,1,terrain_class) ;
        world.setTile(1,2,terrain_hill) ;
        world.setTile(1,3,terrain_river) ;

        console.log(world.getIsWater(1,3));
        console.log(world.getMovementCost(1,2));
    }

    window.onload = function(){
        Main();
    }
</script>
</body>
</html>

[fly weight]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>flyweight </title>
</head>
<body>
경량패턴??<br>
어떤 객체의 수가 너무 많아 좀 가볍게 만들고 싶을때 사용<br>
고유상태와 외부상태로 나눔<br>
<br>
예제 : 지형 만들기<br>
타일(고유상태)과 각 타일들이 갖고 있는 정보(외부상태)<br>
<script>
    function Terrain(movementCost, isWater, texture){

        var movementCost_;
        var isWater_;
        var texture_;

        function _Terrain(){
            this.movementCost_ = movementCost;
            this.isWater_ = isWater;
            this.texture_ = texture;

        }

        _Terrain.prototype.getMovementCost = function(){
            return this.movementCost_;
        };
        _Terrain.prototype.isWater = function(){
            return this.isWater_;
        };
        _Terrain.prototype.getTexture = function(){
            return this.texture_;
        };


        if(!(this instanceof _Terrain )){
            return new _Terrain();
        }

    }

    var CONST_GLASS_TEXTURE = "GLASS_TEXTURE";
    var CONST_HILL_TEXTURE = "HILL_TEXTURE";
    var CONST_RIVER_TEXTURE = "RIVER_TEXTURE";
    var CONST_WIDTH = 10;
    var CONST_HEIGHT = 12;

    function World(){

        var tiles = {};


        function _World(){
            this.glassTerrain_ = [1,false,CONST_GLASS_TEXTURE];
            this.hillTerrain_ = [2,false,CONST_HILL_TEXTURE];
            this.riverTerrain_ = [3,true,CONST_RIVER_TEXTURE];
            this.tiles = tiles;

        }

        _World.prototype.setTile = function(x,y, value){
            this.tiles = this.tiles||{};

            this.tiles[x] = this.tiles[x]||{};
            this.tiles[x][y] = this.tiles[x][y]||"";
            this.tiles[x][y] = value;

        };

        _World.prototype.getTile = function(x,y){

            return Terrain.apply(this, this.tiles[x][y]);
        };


        _World.prototype.generateTerrain = function(){
            for(var x=0; x < CONST_WIDTH; x++) {
                for(var y=0; y < CONST_HEIGHT; y++){
                    if(x % 2 == 0){
                        this.setTile.apply(this, [x,y,this.glassTerrain_]);
                    }else{
                        this.setTile.apply(this, [x,y,this.hillTerrain_]);
                    }
                    if(y % 3 == 1){
                        this.setTile.apply(this, [x,y,this.riverTerrain_]);
                    }
                }
            }
        };

        if(!(this instanceof _World )){
            return new _World();
        }

    }



    function Main(){
        var world = World();
        world.generateTerrain();
        console.dir(world.getTile(1,1).getMovementCost());

    }

    window.onload = function(){
        Main();
    }
</script>
</body>
</html>

댓글 없음:

댓글 쓰기