최고 엔지니어의 꿈을 향해서

[Adapter pattern]

어댑터 패턴이란?

실생활에서 흔히 볼수 있는 어댑터들이란, 110v에서 220v로 바꿔주는 것, 콘센트 끝부분만 바꿔주는것(돼지코), 뭐 즐 다양하다.
소프트웨어에서의 어댑터란 같은 의미다.
양자간의 의사소통만을 위해 어댑터가 존재하며 양끝단은 서로를 몰라도 어댑터로 인한 커뮤니케이션이 이뤄진다.
한국사람과(불어를 모르는) 프랑스인이(한국어를 모르는) 의사소통하기위해선, 한국어와 불어를 동시에 아는사람, 통역사를 데리고 있으면 커뮤니케이션이 이뤄질수 있다. 이때의 통역사가 바로 어댑터에 해당한다고 볼수있다.

어댑터 패턴의 기본원리는 간단하므로
자동차의 예를들어 설명하겠다.

혼다회사의 어코드 자동차는 07년 실적이 저조하여, 08년 새로운 어코드 모델을 선보이기로 했다.
새로운 모델로 전환되면서, 신형엔진으로 교체하는것은 필수인데, 혼다에서 어코드08년신형 엔진개발의 자금력과 시간부족으로 인하여, 신차출시의 난항을 겪게 됐다. 그러던차, 한창 뜨고 있는 현대차 소나타V6 07년의 엔진을 그냥 탑재 하자는 의견이 나왔다. 그렇게 하면, 엔진개발비용과 시간단축등 혼다사에서는 엄청난 이득이 될것이라는 혼다 어느 직원이야기 이다.(바로 해고됐다-_-)
결국 그 직원의 말대로, 현대에 요청하여, 소나타v6엔진을 08년 어코드 모델에 탑재할테니, 좀 엔진좀 싸게 달라고 주문했다. 그런데 처음에는 가능할것 같았던, 자동차 엔진 이식문제가 기술적으로 문제가 발생했다. 어코드차는 지금껏 엔진5단변속으로만 되어있어서, 엔진이외의 모든부품이 그에 맞게 설계 되어있었다. 그러나 현대소나타v6엔진은 8단변속이여서, 서로 궁합이 안맞는 것이였다. 그 엔진을 쓰려면 어코드 자동차 엔진이외의 모든 부품을 8단에 맞게 다시 만들어야 하는데, 불가능한것이였다.
그래서 현대사에게 요청하기를, 8단엔진이 성능이 5단보다 훨씬 좋기때문에, 우리는 8단v6소나타엔진의 장점을 이용하면서 단지 어코드차에 맞게만(5단변속베이스) 설계해 달라고 주문하였다.
현대사에서는 "어댑터"를 만들어서 그렇게 해주겠다고 했다. 정말 재미있다.

그럼 이야기를 간단한 코드로 풀어보면.....

public interface HondaAccord08Engine {
 public void changeEngineMode_5_level();
}
요놈은 혼다 어코드 08년형 엔진 인터페이스 이다. 새롭게 출시되기때문에 새로운 인터페이스를 만들어
앞으로도 이 인터페이스를 사용할 것이라고 한다.

public class AccordCar implements HondaAccord08Engine {
 private String name = "Accord";
 private int year = 2008;
 private int valve = 2;
 private int currspeed = 0;
 private int amount_ventilation = 0;
 
 public void speedUp() {
  currspeed += 2;
 }
 public void Ventilation() {
  amount_ventilation += 20;
 }  
 
 public void changeEngineMode_5_level() {
  System.out.println("드르릉 드르릉 드르릉"); // 변속할때 발생하는 소리
  Ventilation();  // 일련의 필요한 트랜잭션 (변속시)
  speedUp();  
  Ventilation();  
 }
}
요놈이 어코드자동차 엔진..
 
////////////////////////////////////////////////////////////

public interface HyundaiV6newEngine {
 public void changeEngineMode_8_level();
}
현대차에서도 역시나 v6엔진에 대한 인터페이스가 존재한다. 역시나 8단변속이다.

public class HyundaiSonata implements HyundaiV6newEngine {
 private String name = "Sonata";
 private int year = 2007;
 private int valve = 5;
 private int currspeed = 0;
 private int amount_ventilation = 0;
 
 public void increaseSpeed() {
  currspeed += 5;
 }
 public void increaseVentilation() {
  amount_ventilation += 2;
 }  
 
 public void changeEngineMode_8_level() {
  System.out.println("펑펑펑 펑펑펑 펑펑펑"); // 소나타 엔진 변속시 발생하는 소리
  increaseSpeed();  // 소나타 엔진 변속시 발생하는 트랜잭션들....
  increaseVentilation(); // ...
 
 }
}
 요놈은 소나타 자동차엔진 샘플인데, v6 8단 엔진을 장착했다. (*실제로는 엔진클래스 만들어서 인스턴스변수로 넣어주던지 해야할텐데 귀찮아서 생략하고)

그럼 이제 어코드 08년산에 장착할 엔진 5단변속 기준하고, 현대 소나타 8단변속엔진과의 호환을 위해서 새로운 변환 인터페이스를 현대에서 만들었다.


public class EngineAdapter_8_to_5_level implements HondaAccord08Engine {
 HyundaiV6newEngine hyundaiEngine; // 8-level new engine
 
 public EngineAdapter_8_to_5_level(HyundaiV6newEngine hyun) {
  hyundaiEngine = hyun;
 }
 public void changeEngineMode_5_level(){
// 요놈이 바로 실제로 인터페이스호환에 핵심적
  hyundaiEngine.changeEngineMode_8_level();  // 역할을 하는 .....놈
 }
}


그럼 한번 실행시켜보자.

public class AdapterTester {

 public static void main(String[] args) {
  HondaAccord08Engine hondacar = new AccordCar();  // 순수 어코드차
  hondacar.changeEngineMode_5_level();  // 기어 변속시
 
  HyundaiV6newEngine hyundaicar = new HyundaiSonata();  // 순수 소나타 차
  hyundaicar.changeEngineMode_8_level(); // 기어 변속시
 
  hondacar = new EngineAdapter_8_to_5_level(hyundaicar);  // 소나타 엔진을 탑재한 어코드차
  hondacar.changeEngineMode_5_level(); // 기어변속시..(역시 엔진 바꾸는 소리가 소나타차 소리)
 }
}

뭐 이런식이다. 뭐 내가 재밌는 예를 생각하다가 자동차예를 선택했는데, 이해하기 쉬웠는지 모르겠다.
너무 간략하게 설명을 하다보니 빼먹은것도 많고, 귀찮기도 하고,,
이 글의 목적은 아주 처음 감잡을때 읽는용이고 좀더 기술적인 테크닉 세세한 자료들은 역시나 Gof 앤드 웹서치..ㅋㅋ

Posted by 정해권 Trackback 0 Comment 0
사용자 삽입 이미지
건영이의 그림솜씨, 정말 프로답다.^^;
나중에 게임을 같이 만들게 될 날이 언젠간 올것이다.ㅋㅋ
Posted by 정해권 Trackback 0 Comment 0
[Facade pattern]

퍼싸드 패턴이란?
패턴세계에서 몇몇 안되는 간단하믄서 쉬운 패턴. 그러나 언제나 강력한.

일단 한마디로 설명하면, 서브시스템의 복잡성을 심플하게 접근할 수 있는 좀더 추상화된 인터페이스 제공


예를들면, 내가 전기 밥솥을 사용하는데, 전기 밥솥 내부의 원리나 작동원리를 알아야만 밥을 할수 있는것인가? 그렇다면 밥 못먹는다.
일반 사용자들이 알아야 할 것은 오직 전원버튼을 누르는 것뿐.(밥해주세요)

 그럼 밥솥은 알아서 압력게이지를 올리고, 온도를 적정수준으로 도달하게 하고, 시간설정하고, 알아서 다 해준다. 너무 편리하다. 사용자가 일일이 온도 몇도까지 맞추고, 압력게이지 올리고 할필요없이 알아서 다 사용자 대신 해주다니.
그럼 클라이언트에서는 단지 TurnOn(); 만 호출하면, 저 함수 내부에서 복잡한 일들이 벌어진다고 생각하면 된다. 한마디로, 각각의 수많은 트랜잭션을 하나의 클래스로 묶었다고 생각하면 된다.

결국 사용자에겐 편리한 인터페이스를 제공한다. 그리하여, 재사용 할만한 단위를 좀더 확장시켜 준다.
예를들면 압력게이지, 온도센서 등등의 클래스의 재사용 단위 를 압력 밥솥이라는 재사용단위를 확장!!
그렇다고 디테일한 부품을 캡슐화 시켜서 접근할수 없게 만드느냐? 그건 아니다. 양쪽다 가능하기 때문에 바로 이점이 이 패턴의 장점중 하나이다.
결국 큰 시스템간의 종속성만을 생각하고, 작은 아주 디테일한 부분의 종속 결합도는 없앨 수 있다.
여러 단위의 계층화를 시켜서 적용할 경우에도 Facade단위로써만 종속되어있기때문에, 좀더 유연한 시스템을 만들 수 있다.

배고파서 잠시 즐쉬러..






Posted by 정해권 Trackback 0 Comment 0

[Singleton pattern]


싱글톤 패턴에 대해서...

대부분의 사람이 가장 먼저 익히게 되는 패턴중에 하나로, 다른패턴에 비해 목적성과 구현이
상대적으로 쉽다.
싱글톤이란 말그대로, 단하나밖에 생성할 수 없다는 것인데, 가령, 시스템 내에서 단 하나만 만들어져야 하는 객체가 있다면 싱글톤 패턴을 적용하므로써 전체적인 시스템의 안정성을 확보할 수 있다.
일반적으로, 프린터 스풀 (프린트가 여러대라도 스풀은 하나여야 하므로)등이 하나의 예가 될수 있다. 이외에도 설계자가 생각하기에 이 객체는 하나만 만들어져야 한다면 무조건 싱글톤!!! ㅋㅋ(무조건이라는건 위험한 발상 ㅋ)

구현 방법은 가장먼저 생성자를 private로 설정하는것이다. 이렇게 하므로써, 외부에서 객체를 생성할 수 없게 한다.(생성자가 private이면, 객체 생성이 안되며, 상속도 불가). *물론 생성자를 protected로 하므로써 서브클래스를 만들수 있다.*
그럼 어떻게 단 하나만 만든다는 것일까? 클래스 안에 static getInstance()함수를 하나 만들고, 그 안에서 객체생성을 해주는것이다(단 하나만). 외부에서는 생성이 불가 하였지만, 내부에서는 생성이 가능하다(클래스 내부에서 private함수, private변수 접근 가능하니까). 그 안에서 if문으로 생성이 되어있는지 안되어있는지 확인해서 단 하나만 만든다는것이다.

class Singleton {
    private static Singleton single;  // 오직 하나의 객체
   
    private Singleton() { }  // 생성자를 private로 하므로써 외부에서 이 객체 생성 불가
    public static Singleton getInstance() {
        if(single == null)
            single = new Singleton();
        return single;
 }
 이런식으로 말이다. 위의 코드는 lazy instantiation 이며, 이말은 사용자가 getInstance()를 호출할때 비로서 객체가 생긴다는 것이다. 좋은점은 이 객체의 비용이 높을때(자원등) 미뤄왔다가 필요시 만듬으로써, 사용 이전의 자원소모를 방지한다. (컴파일시 처음부터 객체생성과는 달리)
위의 코드 다 좋다. 그러나 위의 코드에 문제점이 있는데, 멀티쓰레드 사용시, 동기화문제가 발생한다.
if(single==null) 부분에서 컨텍스트스위칭이 발생되고, 다른쓰레드에서 또 if(single==null)부분을 돌려버리면 객체 두개 생성되는 식으로 말이다. 이를 방지하기위해 아싸리 처음부터 객체를 만들어 버리는것이다.
public class Singleton {
   private static Singleton single = new Singleton();
 
   private Singleton() {}
   public static Singleton getInstance() {
      return single;
   }
  }
 이런식으로 말이다. 이방법은 컴파일시부터 이객체의 사용시점과 상관없이 미리 만들어 두는것인데,
 리소스 면에서 lazy instantiation 보다 안좋지만은 반면, 속도문제에 있어서는 장점이 될수 있는
 것이다. 뭐 객체 하나 만드는데 속도 문제에 있어 얼마나 메리트가 있느냐 할수 있지만(-_-)
허나, 이 방법은 객체를 처음부터 정의 해야한다는 단점이 ...객체를 정적초기화 시점이 아닌 실행시 주어지는 결과값으로 결정되어야 할때는 문제가 있다. 이런경우 레지스트리를 사용해야 하는데, Gof책을 참조하기 바란다.(-_-)
  이 밖에도 언어에서 제공하는 쓰레드 동기화 키워드 들이 존재하는데 자바의 경우 syncronized라던가 volatile 이라던지 등등 제공해준다.
 * 참고로 전역변수는 생각지도 말자.(전역변수로도 해결할 수 있지만 단점을 극복한 것이 이 싱글톤패턴)
이 싱글톤 패턴 간단하다고 했지만, 의외로 신경써줘야 할 부분이....읔
참고로 패턴의 디테일한 정보는 다 책이나 웹에 있다. 나는 그저 핵심만 설명하는 것이다. 부수적인 테크닉은 역시 책을 봐야 한다 ㅋㅋㅋ
Posted by 정해권 Trackback 0 Comment 1

[Decorator pattern]

데코레이터 패턴이란?

일단, 가장 먼저 집고 넘어 가야 할 것이, oop의 중요한 장점이자 특성중 하나가 inheritance 상속인데
상속의 장점이야 뭐 코드 재사용과 뭐 폴리몰피즘의 기반을 제공해준다고 볼수 있다.
좋은 놈임에는 틀림이 없으나, 그것도 역시 상황에 맞게 써야 좋지, 무턱대고 상속을 써버리면,
시스템이 융통성 없이 무조건 커져버리게 된다는 단점이 있다. 이 상속 기법에 반하여 융통성에 초점을 두고 있는것이 delegation (composition) 인데 요놈의 장점은 런타임시에도 시스템을 유연하게 대처할수 있게 해준다, 허나 코드재사용은 기대하기 어렵게 된다.
이 두가지는 정말 어떻게 보면, 각각 기회비용이 있어서, 신중하게 뭐를 택할 것인지 결정해야 하며, 시스템의 확장성과도 연관지어서 생각해봐야 하고, 그 시스템의 부분이 fixed 쪽에 가까운지, flexible한쪽에 가까운지 설계자의 판단에 의해 결정된다.

그럼 상속이란 것이 컴파일타임시에 코드 자체로서 굳어져 버리는 석고상 이라는것을 알았다. 런타임시에는 코드수정이 불가하므로..
좀더 런타임시에도 새로운 서비스(기능)의 추가를 쉽게 하기위해 Decorator패턴이 등장했는데, 서비스의 추가등을 상속을 이용하는 것보다 유연하게 할수 있는 방법을 제공한다.

설명이 추상적이어서 이해가 잘 안갈수 있으니 구체적인 예를 들어 설명해보면,
자바유저들은 Java I/O에 대해서 알것이고, C#도 뭐 마찬가지 일 것이다.(C#은 안써봐서 모르지만-_-)
엄청나게 많은 I/O관련 클래스들이 존재한다. 그런 즐~많은 클래스들을 보면서 수많은 클래스를 어떻게 다 익힐지, 더군다나 사용법은 약간 특이하기까지 (특이하기보단, 함수 인자로 이전에 만들었던 객체를 넘겨주는 방식을 여러번 취한다)
나도 이 패턴을 알기 전까지는 그 I/O의 복잡성에 손발을 들었었고, 클래스 관계도를 보아도
이놈이 이놈인지, 이름도 다들 비슷한게, 암튼 어질했었다. 결론은 이 패턴을 알면 Java I/O의 관계들도 손쉽게 머리에 들어오게 된다. 왜냐면 Java I/O가 이패턴을 이용해서 설계된것이기땜시.
뭐 다른예들은 실제로 편집기에서 윈도우창에 새롭게 데코레이터를 할때나.., 뭐 활용성에 대해서는 Gof책에도 많이 나와있다.

새로운 예를 들어 코드와 함께 설명하자면, (HeadFirst책에있는 예가 이해하기 아주 쉽기에 같은 예를 들어)
스타벅스에 가보면 다양한 커피가 존재하는데, 기본이 되는 커피 몇개 위에 다양한 것들을 추가할수있는데, 크림이라던지, 모카, 밀크 등등 추가비용만 더 내면 더 추가 할수 있다고 생각해보자.
여기서 생각해봐야 할것은, 여러 조합이 가능하다는것이다. 가령, 기본이 되는 커피 A에 밀크만 추가해서 팔수도 있고, 크림만 추가할수도 있고, 두개다 추가해서 팔수도 있고, 커피B에다가도 똑같이 적용된다. 뭐 이래 저래 조합을 생각해보믄, 엄청나게 많아 지는데, 상속을 이용해보면
Class Coffee{ } // super class
class CoffeeAWithMilk extends Coffee{ }, class CoffeeBWithSugar extends Coffee, class CoffeeAWithMilkandSugar extends Coffee 등등
즐 많아진다. 정적으로 구성하다보니 많아 질수밖에 없는것이다.
뭐 꼭 저렇게 하지 않고 다른방법이 있긴한데, 추가적인 우유, 크림등등에 대한 속성을 Coffee추상클래스에 집어넣은다음에, 기본이 되는 커피만을 서브클래스로 구현하여, 각각의 추가성분은 super클래스Coffee안의 변수등을 통하여, 알아내는 방법인데, 이방법역시, 모든 subclass들이 모두 같은 속성을 (필요없을지라도) 물려받게 된다는 단점이 있다. Coffee클래스가 점점 비대해 질수 있다.
그리하여, 상속으로서 모든조합에 해당하는 클래스를 만든다는건 미친짓이고, 그럼 어떻게 해야 한단말인가? 아까 처음에 언급했던 delegation의 장점을 빌려와야 할것같다.
가장 먼저 가장 superclass격인 class Coffee를 만들고 그 subclass로 기반이 되는 가벼운 클래스 를 선언해준다. (여기서는 커피의 종류?) 그리고 크림이나 설탕이나 등등 추가적인 클래스들의 추상클래스 하나를 상속해준다.(사실 클래스 도식표를 봐야 이해가 빠른데..)
그 추상클래스의 서브클래스로 각각 크림, 우유 등등을 상속해주면 전체적인 디자인은 끝인데, 이게 말로만 하려니 참 어렵...
쓰다보니 개 귀찮아져, 잠시 중단!!!!
자 다시 걍 빠르게 속행;;
public abstract class Coffee {
 String description = "Nothing";
 
 public String getDescription() {
  return description;
 }
 
 public abstract double cost();
}
먼저 가장 윗단계의 추상슈퍼클래스를 만들고 나서 모든클래스가 이 클래스로부터 상속받게 할것이다.
실제 에스프레소커피, 하우스블렌드커피등등 커피 그 자체도 물론 여기서 상속받는것이고, 잡다하게 들어갈 첨가물, 밀크, 모카 등등도 여기에서 상속받게 될것이다. 그로 인하여, 같은 추상클래스로부터 상속받았기때문에, 첨가물이던, 커피 그자체이건 상관없이 서로 호환이 된다는것이다.
public abstract class Condiment extends Coffee {
 public abstract String getDescription();
}
요녀석은 첨가물의 추상클래스이다.

public class Espresso extends Coffee {
 public Espresso() {
  description = "Espresso";
 }
 public double cost() {
  return 1.99;
 }
}
요녀석은 에스프레소이다.
public class HouseBlend extends Coffee {

 public HouseBlend() {
  description = "House Blend";
 }
 
 public double cost() {
  return 0.89;
 }

}
요녀석은 하우스블렌드 커피 ..;;;
////////////////////////////////////////////////////
자 그럼 첨가물 구현
public class Milk extends Condiment {
 Coffee coffee;
 
 public Milk(Coffee coffee) {
  this.coffee = coffee;
 }
 
 public String getDescription() {
  return coffee.getDescription() + ", Milk";
 }
 
 public double cost() {
  return 0.12 + coffee.cost();
 }
}
요녀석은 우유인데 잘 살펴보면, 우유같은 첨가물들은 coffee 인스턴스 변수를 가지고 있기때문에
(바로 composition방식) 행위를 추가시키거나 뭐 덧붙이고 싶은것을 할수있다, 여기에서는 0.12더해준것...이 바로...또한 getDescription함수에서 + Milk 더해준것이 바로 덧붙여진 행위에 해당한다.
.............
public class Mocha extends Condiment {
 Coffee coffee;
 
 public Mocha(Coffee coffee) {
  this.coffee = coffee;
 }

 public String getDescription() {
  return coffee.getDescription() + ", Mocha";
 }
 public double cost() {
  return 0.20 + coffee.cost();
 }
}
모카는 이런식으로 똑같다..
그럼
실제로 어떻게 구동되는지 살펴보면.......................
public class DecoratorPatternTester {
 public static void main(String[] args) {
  Coffee coff1 = new Espresso();
  System.out.println(coff1.getDescription() + coff1.cost());
  coff1 = new Milk(coff1);
  System.out.println(coff1.getDescription() + coff1.cost());
 }
}
요런식으로 .............하는것이다. 자바의 I/O 라이브러리 쓸때랑 같은 형식인걸 알수있다.
자 지금은 단지 데코레이터 패턴에 대해서만 언급한 것이고, 생성과정에서의 오류나 실수를
방지하기위해서는 팩토리관련 패턴이 참여하게 되는데, 그것은 다음장에서 설명하겠다.
중요한것은 데코레이터패턴에서 눈여겨봐야 할것은 래퍼객체 이전의 객체에 대해서는 알수도, 알아서도 안되는것이다. 이 디자인패턴이 생겨나게 된 이유중에 하나가 이전의 데코레이터가 뭔지 상관안하는 상태에서 덧붙이는 것이기때문에, 그런 일련의 생성과정은 사용자가 알아서 하는것이다.
흠........지금까지의 설명은 아주 베이직한 핵심 원리 였고, 좀더 디테일한 정보는 역시나 Gof책에서..
** 디자인패턴 기본작동원리를 모르는상태에서 GOF책 보면 이해절대 불가이다.장담한다.
    그러나 알고보면 새로운 진리를 발견하게 된다...**



Posted by 정해권 Trackback 0 Comment 0
[Observer pattern]

간만에 방학맞이 기념으로 옵져버 패턴에 대해 간략하게 무엇인지 적어보겠다.
내가 생각하기에 패턴중에서도 중요순위 넘버 파이브 안에 들어간다.
실제 이패턴을 이용하는 경우가 많이 있어서, 나중에 다른 테크닉을 익힐때, 이 패턴을 알아두면 도움이 될듯 싶다.( 대표적으로 MVC모델에서 쓰이며, 자바의 경우에서 보면 RMI, JavaBeans, Swing 등등 많이 쓰인다)

MVC패턴은 정말로 꼭 알아두어야 하는 것이기 땜시 다음번에 설명을 꼭 하겠다. 실제 3-tier 모델로
설계할경우 많이 이용된다.

옵져버 패턴은 Subject와 Observer 이렇게 나뉘어 있는데, Subject에서 데이타를 변경하면 그에 종속되어 있는 수많은 Observer들이 영향을 받게 된다.

비유해보면, 신문사의 신문을 구독자에게 모두 전달하는 것과 같다. 단 전달순서에 대해 의존해서는 안된다.

대표적인 예가, 엑셀에서 데이타를 변경하면 그에 해당하는 각가지 visual diagram이 변경된다.
도표 모양이 타원이던 막대그래프이건간에 상관없이 데이타를 정확하게 표현해 주기만 하면된다.
이런경우 데이타와 표현부분에 있어서 sync를 맞춰줘야 하는데, 옵져버패턴을 사용안하고 구현하게 되면, 데이타와 표현부분의 대한 의존도가 높아지고, 데이타 싱크 부분에서 개런티를 보장하기 위해 지저분한 조건문 같은게 포함될 것이다.

그럼 옵저버 패턴을 이용하면, 얻게 되는 장점중에 하나가 loose coupling 이고, 그 말 즉슨, Subject와 Observer 각각 재사용이 좀더 용이해 진다 이것이다. 동적으로 observer에 해당하는 객체를 쉽게 추가/삭제 할수 있다.

그럼 이해를 돕기 위해, 예를 들어 설명을 하겠다.
미국 캘리포니아에 EarthQuake라는 회사가 있다. 그 회사가 하는일은 전세계 지진관련 정보를 수집하며, 필요시 정보를 제공하기도 한다. 정보중에는 어느지역이 지진가능성이 있는지, 발생되었는지에 대한 좌표도 포함한다.
어느날 지진관련 프로젝트를 맡은 팀이 회사에 컨택을 하여 정보제공여부를 확인한뒤, 승락받았다.
이제 해야할 일은 그 데이타를 가지고, 웹상에서 구글맵위에 매핑시켜주는 일과, 그 데이타를 가지고 각가지 도표로도 표현해 주어야 하며, (실시간으로) 뭐 이런식의 일을 해야한다.
핵심은 한가지 데이타를 가지고 다양한 프레젠테이션을 만들어 낼수 있다는 것이다. (뭐 단지 프레젠테이션에만 국한되는것은 아니지만) ### 여기서 왜 꼭 패턴을 사용해야 하는가 라는 물음이 나올수 있는데 결론은 안써도 된다, 쓰건 안쓰건 개발자 마음이며, 이같은 상황에 옵져버패턴을 적용하는 경우라면 개발자의 생각은 다음과 같을 수 있다. 앞으로 점점 지진자료를 가지고 실시간으로 처리해야 하는 프레젠테이션 부분의 수가 시간이 가면 갈수록 점점 늘어날 테이고, 데이타부분과 프레젠테이션 부분의 결합을 될수 있는한 약하게 하여, 나중에 꼭 지진좌표가 아니더라도, 다양한 데이타를 가지고 처리를 하기 위해서 적용했다 라고)

그럼 다시한번 코드를 훑어 보면서 이해를 돕자.

1. 지진관련 데이타 클래스 (요놈이 실제 subject에 해당하는 놈, 인터페이스로 만들자, 추상적인 결합을 만들기 위해)
public interface Subject {
   public void registerObserver(Observer o);  //옵저버로 등록하기 위해
   public void removeObserver(Observer o);  // 옵저버를 리스트에서 제거하기 위해
   public void notifyObservers();  // 리스트에 들어있는 모든 옵저버에 통보를 한다.(update(..)호출)
}

2. 위에 있는 인터페이스를 상속받아, 실제 지진관련 클래스를 작성.
public class Earthquake implements Subject {
   private ArrayList observers; // 옵저버 보관리스트, 배열말고 다른 자료구조 이용해도 상관없음.
   private float earthquakePosition;
   private float earthquakePressure;
   // 등등등의 데이타들.

   public Earthquake() {  // constructor
       observers = new ArrayList();
   }
   public registerObserver(Observer o) {  // 인터페이스 구현
      observers.add(o);  // 배열에 추가
   }
   public removeObserver(Observer o) {  인터페이스 구현
       if(o의 인덱스가 있으면...)
      observers.remove(i); // something like that
   }
   public void notifyObservers() {
       for(int i=0; i< observers.size(); i++) {
          Observer ob = (Observer)observers.get(i); // 옵저버를 불러내어
          observer.update(earthquakePosition, earthquakePressure); //인자는 전달하고싶은것들
        }
   }
   public void mesurementsChanged() {
        if(가져온 루틴이 갱신됐거나 옵저벼들에게 알리고 싶으면)
            notifyObservers();
   }
   public void retrieveMesurements() {
      // 회사로부터 관련 자료를 가져오는 루틴
      mesurementsChanged();
  }
 /////////////////////////////////////////////////////////////////////////
3. 옵져버 (일명 신문구독자)의 코드
   * 먼저 옵져버의 기본 인터페이스를 만들자 (loose coupling)
  public interface Observer {
      public void update(float earthquakePosition, float earthquakePressure);
  }
  * 실제 옵저버들 구현
   public class MappingtoGooglemap implements Observer {
        private float earthquakePosition;
        private earthquakePressure;
        private Subject earthquakeData;
        public MappingtoGooglemap (Subject earthquakeData) {  // constructor
                this.earthquakeData = earthquakeData; // 나중에 리스트에서 빠지기위해
                earthquakeData.registerObserver(this); // 옵저버리스트에 가입함
        }
        public void update(float earthquakePosition, float earthquakePressure) {
           this.earthquakePosition = earthquakePosition;
           this.earthquakePressure = earthquakePressure;
           draw();
        }
        public void draw() {  // 이함수에 대한 공통 인터페이스, 개런티를 원한다면, 인터페이스를 만
                                      // 든뒤 인터페이스 구현
           // earthquake자료들을 가지고 실제 구글웹에 매핑해주는 소스
        }
     public class StoretoTexfile implements Observer {
           // 위에 있는 코드대로 ..
 
           public void draw() {
                 // earthquake자료들을 실제 파일로 저장..
           }
      }
///////////////////////////////////////////////////////////////////////////////
이런식으로 전반적인 모습이 이렇다. Subject와 Observer들 사이에서의 데이타 전송은,
서브젝트쪽에서 데이타 변경시 옵저버들에게 알려주는 pushing방법과 옵저버들 자신이 데이타를 원한경우 서브젝트에게 데이타를 요구하는(getter메서드를 통하여) pulling 방식 두가지가 있는데,
물론 장단점이 다 있다. 수많은 옵저버들이 존재 할텐데 각각 옵저버들이 원하는 데이타가 다를것이다.
이럴경우 subject입장에서는 모든 옵저버가 원하는 데이타를 일일이 보내주기 거시기 하기때문에
이럴경우는 pulling방식을 써서 옵저버가 직접 서브젝트에게 getXXX() 등의 함수를 호출하여 값을 뽑아내는 식으로...이럴경우는 좀더 확장에 대해 열려있다고 보믄되고, 하지만 이런경우 옵져버들이 일일이 요청해야 하는 번거로움이 증가되고, 자료 교환의 트랜잭션 수가 증가된다고 볼수있다.Getter함수를 여러번 호출해야 할테니까.

한마디로 옵저버 패턴은 네트웍 개념에서 보면 broadcast로써, 옵저버수와 상관없이 리스트 등록되어있는 모든 객체에게 메시지를 전달하는 것이다. 메시지의 처리여부는 observer들이지 subject는 상관할바 아니다.
뭐 이외에도 옵저버패턴의 많은 장단점 활용가치 등이 있으나, 자세한것은 Gof책을 참조하기 바란다.


Posted by 정해권 Trackback 0 Comment 1


티스토리 툴바