2013년 12월 17일 화요일

static 영역에서 싱글턴 구현 (inner class)



public class Stage{

  private Stage(){}


  private static class StageSingletonHolder{
    static Stage instance = new Stage();
  }

  private static Stage getInstance(){
    return StageSingletonHolder.instance;
  }
}




2013년 12월 16일 월요일

전도의 유혹


종교 운동의 목적은 사회를 병들게 만들고 그 치유책으로 자신들의 종교를 제시하는데 있다.



사람들의 뇌 구조는 스스로 의문을 제기함과 동시에 다시 스스로 그 의문에 답을 하려는 매우 독특한 형질로 구성되어 있어요. 뇌는 불편함을 느끼면 스스로 그것을 해소하기 위해 동작하죠. 그리고 신경과학자들과 종교학자들의 견해에 의하면 종교는 이런 특별한 구조를 가진 뇌를 위안해준다고 합니다.

종교는 뇌가 정말 궁금해하는 존재의 원리와 이유, 또는 사후세계에 대해 설명해주고(비록 거짓일지라도), 불편함을 해소해주며, 만족감을 제공하죠. 

불확실한 미래 또는 내세의 삶은 사람들에게 스트레스를 줍니다. 
사람들은 스트레스로 인한 고통을 줄이기 위해 휴일, 휴가, 운동, 잠, 오락, 마약, 알콜, 섹스 등에 의존하지만, 종교는 이것은 일시적인 방편일 뿐,  근본적인 치유책은 될 수 없다고 얘기합니다.

이런 스트레스의 정점을 찍고 있는 사람들앞에서 종교는 손짓합니다. 그리고 말하죠.

내세의 삶이 있으니 의심을 풀고 믿음으로써 평화를 얻고 구원을 받으라고 말이죠. 

종교는 믿음을 분비합니다. 종교활동을 하는 동안, 사람들의 뇌는 조용하면서도 강력한 화학작용을 일으켜 샹그릴라를 경험하는 듯한 초월적인 느낌을 받는다고 합니다. 그리고 그 느낌은 지금껏 자신이 중요하게 여겼던 다양한 가치들을 일순간에 소실시킬 정도로 강력하고 온몸의 파장을 지배하죠. 더해서 그 느낌에 의존해, 그 느낌을 갖지 못했다고 판단되는 타인들보다 스스로 높은 자리에 오른 다음, 그들을 내려다보며 자신이 겪고 있는 느낌을 전달하고자 합니다. 그것을 "전도"라고 부르지요.

어쩌면 종교의 진정한 구원은 초월적인 천국 같은 것이 아니라, 생물학적 영역일지도 모르겠네요.




2013년 12월 15일 일요일

위임과 리디렉션

 

 



디자인 스페이스라는 EDP 개념에서 메서드 호출 의존성 이론중 위임과 리디렉션의 그래프예요.

x는 메서드를 나타내고, y는 오브젝트를 나타냅니다.

 

유사도는 값이 클수록 비슷해지고, 값이 작을수록 달라지죠.

 

이래뵈도 졸트상을 수상한 그래프예요 


그래프를 보시면 알겠지만, 위임은 오브젝트 유사도와 메서드 유사도의 값이 공통적으로 낮고

리디렉션은 오브젝트 유사도는 낮지만 메서드 유사도는 높은 것을 알 수 있어요.

 

 

지금부터 그래프를 토대로 해설 들어갑니당 ~


위임은 소프트웨어 설계 분야에서 다양하게 쓰이는 광범위한 뜻의 단어입니다.

여기에서 위임을 정확하게 정의하자면, 메서드 호출이 일어나는 두 객체와 두 메서드가 서로 다름을 의미합니다.


[위임 예시]

 

 

class VicePresidentOfSales

{

public :

    void increaseQuarterlySales();

};

 

class CEO

{

private :

    VicePresidentOfSales * m_vicePresidentOfSales;

    

public :

    void increaseProfits(){

        m_vicePresidentOfSales -> increaseQuarterlySales();

    }

}



위임이라는 단어를 사용한 이유는 호출 메서드가 타겟에게 
"내가 내 일을 끝낼 수 있게 너는 이 작업을 맡아줘"라고 말하면서, 자신의 목표 작업을 제외한 일부 작업을 나눠주기 때문입니다.

기업의 CEO가 여러 부서를 담당하는 부사장들에 업무를 위임하는 것과 마찬가지예요.
CEO는 "기업 운영"이라는 업무가 있지만, 각 부사장에겐

- 사원 인력 관리
- 재무 건전성 확보
- IT기술에 대한 투자와 효율적 운용

등의 업무가 있습니다. CEO는 자신의 업무가 아니라 생각되지만 자신의 업무를 성공적으로 완수하기 위해 필수적인 업무를 각 부사장에게 수행하도록 요구하죠.


이런 위임을 리디렉션과 비교해 보겠습니다.
리디렉션의 경우, 호출 메서드는 다른 객체에게 어떤 작업을 하도록 요청하긴 하지만, 자신이 해야 할 작업과 똑같은 작업을 요청한다는 점이 위임과 다릅니다. 


다른 객체에 자신의 작업량 중 일부를 넘기되, 부분적인 작업이 자신의 전체적인 작업과 거의 비슷합니다. 


[리디렉션 예시]

 

@interface Painter {}

-(void) painterCar : (Car) car;

@end

 

 

@interface PainterShopManager {}

Painter subPainter;

 

(-void) painterCar : (Car) car;

@end

 

 

@implementation PainterShopManager

 

(-void) paiterCar : (Car) car{

    [subPainter painerCar : car];

}

 

@end




리디렉션은 한 가지의 특정한 작업이 여러 대의 병렬 유닛으로 분기되어 진행된 후, 각 유닛의 작업 결과가 다시 한 라인으로 합쳐져서 다음 스테이션으로 넘어가는 조립 라인과 상당히 비슷합니다.

자신과 부하의 작업 유사성으로 인해 이런 식의 작업 분배가 위임이 아니라 리디렉션이 됩니다.
그러므로 리디렉션은 메서드 유사성은 높지만 서로 다른 유닛들이 병렬 프로그래밍을 수행한다는 점에서 객체 유사도는 낮은 분포도를 보이는 것이죠.



집단지성 엘리멘트 중에서.






1 : n(one to many) 관계의 데이터를 저장하는 자료구조

package util;

 

public interface IDataStore {

 

public int on(String $type, String $value);

public void off(String $type, Object $object);

public void off(String $type, int $id);

public void off(String $type);

public void off();

public void trigger(String $type, Object $object);

public void trigger(String $type);

 

}

 

 

 

어떤 특정한 스트링키에 매핑시킬 수 있는 여러 데이터를 가질 수 있는 자료구조예요.

상황에 따라 키가 스트링이 아닌 오브젝트로 바꿔서 사용해도 됩니다. 그럼 더욱 더 넓은 관계의 데이터 구조를 다룰 수 있게 되겠죠. 값이 아닌 키조차도 오브젝트형이라면.

 

내부적으론 자바의 Map과 배열리스트라는 자료를 응용해서 만든거구요.

 

C++의 STL을 사용하면 자바보다 훨씬 쉽게 구현할 수 있어요. STL은 구조체의 성격이라서 얼록이라는 과정이 필요없고 이 부분은 이런 자료구조의 로직에서 자바보다 더 쉬운 응용이 가능하더라구요. 그래서 쉬운 C++보다는 "아주 조금" 더 생각해야할 부분이 있는 자바로 구현했어요.

 

 

on이라는 메서드는 하나의 특정 키에 여러개의 값을 매핑할 수 있게 등록하는 기능을 가집니다.

off는 등록한 값을 지우는 기능을 하죠

 

trigger는 값을 꺼내는 역할을 합니당. 지금은 그냥 리턴 타입이 없게 만들어뒀어요.

테스트용에 불과하니까요 ㅎㅎ

 

 

 

package until;

 

import java.util.ArrayList;

import java.util.HashMap;



public class DataStore implements IDataStore{

private HashMap<String, ArrayList<Object>> index = 

new HashMap<String, ArrayList<Object>>();

private static DataStore instance;

private DataStore(){}

public static DataStore sharedObject(){

if(instance == null){

instance = new DataStore();

}

return instance;

}

 

@Override

public int on(String $type, String $value) {

if(!this.index.containsKey($type)){

this.index.put($type, new ArrayList<Object>());

}

this.index.get($type).add($value);

return this.index.get($type).size();

}

 

@Override

public void off(String $type, Object $object) {

if(!this.index.containsKey($type)) return;

if(this.index.get($type).isEmpty()) return;

if(!this.index.get($type).contains($object)) return;

this.index.get($type).remove($object);

}



@Override

public void off(String $type, int $id) {

if(!this.index.containsKey($type)) return;

if(this.index.get($type).isEmpty()) return;

if($id >= this.index.get($type).size()) return;

this.index.get($type).remove($id);

}

 

@Override

public void off(String $type) {

if(!this.index.containsKey($type)) return;

if(this.index.get($type).isEmpty()) return;

this.index.get($type).clear();

}

 

@Override

public void off() {

this.index.clear();

}

 

@Override

public void trigger(String $type, Object $object) {

if(!this.index.containsKey($type)) return;

if(!this.index.get($type).contains($object)) return;

System.out.println($object);

}

 

@Override

public void trigger(String $type) {

if(!this.index.containsKey($type)) return;

for(int i=0; i<this.index.get($type).size(); ++i){

System.out.println(this.index.get($type).get(i));

}

}

}



로직을 보시면, 데이터 스토어는 맵을 갖고 있고 이 맵은 키에 매핑시킬 자료로 프리미티브값이 아닌 "배열"을 갖고 있어요. 

on에서 데이터를 등록할 때, 연관키가 없을 경우에만 이 키에 대응시키는 배열을 얼록해주는 논리를 쓰고 있죠. 이 부분에서 STL보다는 살짝 더 고민을 해줘야하는 것 같아요. 얼록이라는 과정때문이죠.

 

 

테스트 코드는 아래와 같아요.


/* 데이터 스토어를 싱글턴 유형으로 생성 */

IDataStore dataStore = DataStore.sharedObject();

 

/* 객체에 사람이라는 키로 도킨스, 매트, 해리스를 저장 */

dataStore.on("사람""도킨스");

dataStore.on("사람""매트");

dataStore.on("사람""해리스");

 

/* 객체에 동물이라는 키로 강아지, 고양이, 사자를 저장 */

dataStore.on("동물""강아지");

dataStore.on("동물""고양이");

dataStore.on("동물""사자");

 

/* 사람이라는 키로 저장되어있는 모든 데이터를 출력 */

dataStore.trigger("사람");

System.out.println("----------");

/* 동물이라는 키로 저장되어있는 모든 데이터를 출력 */

dataStore.trigger("동물");

System.out.println("----------");

/* 사람이라는 키에서 john이라는 값을 지움.(그러나 john이라는 값이 저장되어 있지 않기 때문에 아무런 일도 발생하지 않음 */

dataStore.off("사람","john");

 

/* 사람이라는 키에서 해리스라는 값을 지움.(위에서 저장했던 해리스가 지워짐) */

dataStore.off("사람""해리스");

 

/* 다시 출력. 사람이라는 키에서 해리스만 지워진것을 확인할 수 있음 */

dataStore.trigger("사람");

System.out.println("----------");

dataStore.trigger("동물");

 

System.out.println("----------");