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>

2016년 6월 19일 일요일

게임프로그래밍 패턴 - 커맨드패턴을 이용한 이동키로 화면 움직이기 구현

아래는 원본 함수
handleInput에 if문으로 각각의 함수를 호출 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>command pattern</title>
    <style>
        #unit {
            position: absolute;
            background-color: olivedrab;
            top:100px;
            left:100px;
            display:block        }
    </style>
</head>
<body>
원본소스
<div id="unit">
    unit
</div>
<script>
    document.addEventListener("keydown", handleInput, false);
    function handleInput(e){
        var keyCode = e.keyCode;
        if(keyCode == 38){
            up();
        }else if(keyCode == 40){
            down();
        }else if(keyCode == 37){
            left();
        }else if(keyCode == 39){
            right();
        }
    };


    function unit(){
        var target = document.getElementById('unit');

        return {
            "x" : parseInt(getStyle(target,"left"),10),
            "y" : parseInt(getStyle(target,"top"),10),
            "body" : target.style        };
    }
window.onload= function(){
    console.log(unit().x);
};


</script>

<script>


    function getStyle(el, styleProp) {
        var value, defaultView = (el.ownerDocument || document).defaultView;
        // W3C standard way:        if (defaultView && defaultView.getComputedStyle) {
            // sanitize property name to css notation            // (hypen separated words eg. font-Size)            styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
            return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
        } else if (el.currentStyle) { // IE            // sanitize property name to camelCase            styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
                return letter.toUpperCase();
            });
            value = el.currentStyle[styleProp];
            // convert other units to pixels on IE            if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
                return (function(value) {
                    var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
                    el.runtimeStyle.left = el.currentStyle.left;
                    el.style.left = value || 0;
                    value = el.style.pixelLeft + "px";
                    el.style.left = oldLeft;
                    el.runtimeStyle.left = oldRsLeft;
                    return value;
                })(value);
            }
            return value;
        }
    }

function up(){
    var target = unit().y;
    return unit().body.top = suffixValue(target, -3);
}

    function down(){
        var target = unit().y;
        return unit().body.top = suffixValue(target, +3);
    }

    function left(){
        var target = unit().x;
        return unit().body.left = suffixValue(target, -3);
    }

    function right(){
        var target = unit().x;
        return unit().body.left = suffixValue(target, +3);
    }

function suffixValue(target, value){
    var suffix = "px";
    return (target + value)+suffix;
}

</script>
</body>
</html>


커맨드 패턴을 이용하여 각각의 메서드 호출을 실체화 함, and undo, redo 구현

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>command pattern</title>
    <style>
        #unit {
            position: absolute;
            background-color: olivedrab;
            top:100px;
            left:100px;
            display:block        }
    </style>
</head>
<body>
메서드의 호출을 실체화 함
<div id="unit">
    unit
</div>
<script>

    function getStyle(el, styleProp) {
        var value, defaultView = (el.ownerDocument || document).defaultView;
        // W3C standard way:        if (defaultView && defaultView.getComputedStyle) {
            // sanitize property name to css notation            // (hypen separated words eg. font-Size)            styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
            return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
        } else if (el.currentStyle) { // IE            // sanitize property name to camelCase            styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
                return letter.toUpperCase();
            });
            value = el.currentStyle[styleProp];
            // convert other units to pixels on IE            if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
                return (function(value) {
                    var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
                    el.runtimeStyle.left = el.currentStyle.left;
                    el.style.left = value || 0;
                    value = el.style.pixelLeft + "px";
                    el.style.left = oldLeft;
                    el.runtimeStyle.left = oldRsLeft;
                    return value;
                })(value);
            }
            return value;
        }
    }
    document.addEventListener("keydown", handleInput, false);
    function handleInput(e){          //메인함수
        var keyCode = e.keyCode;

        var pressDispatcher = {       //command dispatcher            37 : new LeftCommand,
            38 : new UpCommand,
            39 : new RightCommand,
            40 : new DownCommand,
            89 : new RedoCommand,
            90 : new UndoCommand        };

        var button = pressDispatcher[keyCode];
        var isPress = (keyCode in pressDispatcher);
        if(isPress) button.execute();


    };

    var Command = function(){
        var x = unit().x, y = unit().y;
        return {
                "execute" : function(){

                    console.log("origin command execute");
                },
                "undo" : function(){
                    if(this.beforeLocation.length > 0){
                        var locationData = this.beforeLocation.pop();
                            unit().move(locationData);
                            this.redoHistoryWrite(locationData);
                    }
                },

                "redo" : function(){
                    if(this.afterLocation.length > 0){
                        var locationData = this.afterLocation.pop();
                        unit().move(locationData);
                        this.undoHistoryWrite(locationData);
                    }
                },
                'beforeLocation' : [],
                "undoHistoryWrite" : function(){

                    this.beforeLocation.push([unit().x,unit().y]);
                },

                'afterLocation' : [],
                "redoHistoryWrite" : function(){

                    this.afterLocation.push([unit().x,unit().y]);
                }
            };
    }();


    function RedoCommand(){

        function _RedoCommand(){
            this.execute = function(){
                this.redo();
            };

        }
        //@extends        _RedoCommand.prototype = Command;

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


    function UndoCommand(){

        function _UndoCommand(){
            this.execute = function(){
                this.undo();
            };

        }
        //@extends        _UndoCommand.prototype = Command;

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

    function UpCommand(){

        function _UpCommand(){

            this.execute = function(){
                this.undoHistoryWrite();
                up();
            };

        }
        //@extends        _UpCommand.prototype = Command;

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


    function DownCommand(){

        function _DownCommand(){
            this.execute = function(){
                this.undoHistoryWrite();
                down();
            }
        }
        //@extends        _DownCommand.prototype = Command;

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


    function LeftCommand(){

        function _LeftCommand(){
            this.execute = function(){
                this.undoHistoryWrite();
                left();
            }
        }
        //@extends        _LeftCommand.prototype = Command;

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


    function RightCommand(){

        function _RightCommand(){
            this.execute = function(){
                this.undoHistoryWrite();
                right();
            }
        }
        //@extends        _RightCommand.prototype = Command;

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


    function unit(){
        var target = document.getElementById('unit');

        return {
            "x" : parseInt(getStyle(target,"left"),10),
            "y" : parseInt(getStyle(target,"top"),10),
            "body" : target.style,
            "move" : function(arr){
                target.style.left = arr[0]+"px";
                target.style.top = arr[1]+"px";

            }
        };
    }
window.onload= function(){
    /*console.log(unit().x);*/};


</script>

<script>



function up(){
    var target = unit().y;
    return unit().body.top = suffixValue(target, -3);
}

function down(){
    var target = unit().y;
    return unit().body.top = suffixValue(target, +3);
}

function left(){
    var target = unit().x;
    return unit().body.left = suffixValue(target, -3);
}

function right(){
    var target = unit().x;
    return unit().body.left = suffixValue(target, +3);
}

function suffixValue(target, value){
    var suffix = "px";
    return (target + value)+suffix;
}

</script>
</body>
</html>

2016년 2월 25일 목요일

[classic asp] 엑셀에서 alt+enter 값 추가

개행문자에 대해서 치환을 해줄때 그냥 <br />을 넣어줄경우 밑에 셀로 한개 한개씩 생김
br 스타일에 <br style='mso-data-placement:same-cell;'> 이런식으로 넣어주면
alt+enter 값 들어간거처럼 들어감

2016년 2월 22일 월요일

추상 팩토리 패턴 (abstract pattern)


추상 팩토리 패턴(Abstract factory pattern)은 다양한 구성 요소 별로 '객체의 집합'을 생성해야 할 때 유용하다. 이 패턴을 사용하여 상황에 알맞은 객체를 생성할 수 있다.
대표적인 예로, 자바 프로그래밍 언어의 GUI 구성 요소인 AWT/Swing 라이브러리의 룩 앤드 필 변경 기능을 들 수 있다. 메탈마이크로소프트 윈도맥 OS 등의 모양으로 변경할 수 있다. 이에 따라 추상 팩토리에 있는 기본 팩토리 객체가 변경된다. 그러면 이후로 생성되는 GUI 객체들은 전부 해당 룩앤필에 따른다.

------------------------------------------------------
다이어그램 

abstract factory ---> abstract product
        ↑                          ↑
concrete factory ->   concrete product

------------------------------------------------------

다이어그램 구상

가상공장   ---> 차, 신발, 시계 등등 공장 제품 
   ↑                 ↑   
  공장      ->      완제품

------------------------------------------------------
구현 

<!doctype html>
<html lang="ko">
 <head>
  <title>abstract factory</title>
 </head>
 <body>
 <script>
 // 공장에서 여러 제품들을 만든다고 생각 하면 쉬움 
 
  var AbstractFactory ;  // 추상화된 공장(생산, 이름 등등의 기능 을 갖고 있을거임)
  var ConcreteFactory ;  // 구현된 공장(실질적 공장의 이름과, 작동에 대해 기술되 있을거임)
  var AbstractProduct ;  // 공장에서 생산할 제품들의 추상화된 인터페이스 (차, 시계, 신발 등등)
  var ConcreteProduct ;  // 해당 제품을 공장에서 만든다 생각 

  AbstractFactory = function(){
   this.location ='서울';
   this.companyName = 'nice';
  }; 

  AbstractFactory.prototype = {
   create : function(){
    console.log(this.product);
   },
   set : function(product){
    this.product = product.name;
   }
  };

  function ConcreteFactory(){
   var abstractFactory = new AbstractFactory
    abstractFactory.location = '경기';
    abstractFactory.companyName = 'nic';

   return abstractFactory;
  }

  function AbstractProduct_car(){
   this.name = 'car';
  }

  function AbstractProduct_shoes(){
   this.name = 'shoes';
  }


  var concreteProduct = new ConcreteFactory;
  var car = new AbstractProduct_car;
  var shoes = new AbstractProduct_shoes;
   concreteProduct.set(car);
   concreteProduct.create();
   concreteProduct.set(shoes);
   concreteProduct.create();
  


 </script>
 </body>
</html>

룩앤필(look and feel)

룩 앤드 필(Look and feel)은 마케팅, 브랜딩, 상표화와 같은 분야와 제품의 내용에 쓰이는 용어로, 사용자의 제품 체험과 겉모양, 인터페이스의 주된 기능을 나타낸다.
소프트웨어 디자인에서 룩 앤드 필은 그래픽 사용자 인터페이스의 관점에서 쓰이며 색, 모양, 레이아웃, 글꼴(룩)뿐 아니라 단추, 상자, 메뉴와 같은 동적인 요소의 동작(필)을 수반하는 디자인의 측면을 이루고 있다. 룩 앤드 필은 또한 API의 관점을 가리키기도 하며, 이 API의 관점 중 대부분은 기능적인 특성과 관련되어 있지는 않다. 룩 앤드 필이라는 용어는 소프트웨어웹사이트 두 곳에서 쓰인다.
룩 앤드 필은 다른 제품에도 적용할 수 있다. 이를테면, 문서에서 룩 앤드 필은 그래픽 레이아웃(문서 크기, 색, 글꼴 등)과 문체를 일컫기도 한다. 기기 환경에서 룩 앤드 필은 제품 라인의 제어, 디스플레이의 일관성을 일컫기도 한다.

위키 참조
https://ko.wikipedia.org/wiki/%EB%A3%A9_%EC%95%A4%EB%93%9C_%ED%95%84

2016년 2월 21일 일요일

자바스크립트 프록시 패턴(proxy pattern )

UML
[client] ---> [subject](interface) ← [proxy]
                        ↑
                 [real subject]


장점 : 사용자로부터 최적화와 관련내용을 감추어 코드를 단순하게 해준다.
단점 : 실제 객체가 생성되어 있다면, 오버헤드가 됨


proxy(대리자) : real subject로의 참조를 관리하고 접근을 제어한다. real subject가 구현하고 있는 인터페이스를 구현하므로 real subject를 사용하는 것처럼 사용할 수 있다.
subject : proxy와 real subject가 구현하고 있는 인터페이스, 이 인터페이스를 통해 이들이 상호 교환적으로 사용될 수 있다.
real subject : proxy가 대리하고 있는 실제 객체


<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <title>proxy</title>
 </head>
 <body>
<script>

 var urls = [];
 var image = function(){
  return new proxyimage;
 }; //subject
 var realimage = function(){
  this.getimg = function(){
   console.log(urls);
  };
 }; //
 var proxyimage = function(){
  this.getimg = function(url){
   if (urls.indexOf(url) == -1){ // real subject 로드 여부 판단
    urls.push(url);
   }else{
    return (new realimage).getimg();
   }
  };
 }; //

 var client = new image;
  client.getimg('imgurl return'); //proxy 로드 전 
  client.getimg('imgurl return'); //proxy 로드 후 real subject 로드 
</script>
 </body>
</html>







2016년 2월 20일 토요일

템플릿 메소드 패턴(template method pattern)

상위 클래스에서 처리의 흐름을 제어하고 하위클래스에서 처리의 내용을 구체화한다.
여러클래스에서  공통되는 사항은 상위 추상클래스에서 구현하고, 각각의 상세부분은 하위클래스로 구현한다, 코드의 중복을 줄이고 리팩토링에서 유리한 패턴으로 상속을 통한 확장 개발 방법으로 전략패턴과 함께 가장 많이 사용되는 패턴중 하나


[abstract class]
+ templateMethod();          
# subMethod();

  ↓↓↓↓↓

[ConcreteClass]
+subMethod();


== source ==
abstract class abcls{
   public templeteMethod(){}
   public abstract subMethod(){}
}

class concls extends abcls{
   @override
   public subMethod(){}
}