2017년 5월 24일 수요일

[python] 파이썬으로 twilio써보기

twilio는 SMS/MMS를 보내는 서비스이다. 모듈을 받아서 바로 그냥 쓰기만 하면 된다.(아니 물론 회원가입을 하고 인증키를 받은 후)
서비스는 아주 잘 되는 것으로 보이나 문제점은 한국에서 지원이 안된다. (아주 치명적이다.)
그래도 어떻게 쓰는지는 한 번 적어놔야겠다.
from __future__ import unicode_literals
from twilio.rest import Client

account_sid = "AC...내가 받은 아이디"
auth_token = "273 내가 받은 인증코드"

client = Client(account_sid, auth_token)

message = client.messages.create(
    body="Hello, I'm Younghwan Nam. I love you All. See you.",
    to="+8210000000",
    from_="+13399999999"  # 발급받은 twilio 번호
    )

print message.sid

2017년 5월 17일 수요일

[java][bitwise] 자바 비트연산에 대해서...

분명 학원에서 비트연산이라는 건 배워본 적이 없다. 연산이라하면 더하기, 빼기, 곱하기, 나누기, 그리고 모드(%) 뿐이었다.
비트연산을 쓴 적은 자바스크립트를 사용할 때 써본적은 있지만 서버에서 써본 적은 없다.(물론 알게 모르게 자바에서 네트워크 통신같은 것을 할 때 쓰고 있을 것이다.)
비트 연산은 나름 중요해 보인다.
알아두고 가끔씩 써봐야 나중에 남이 만든 코드를 보았을 때, 읽을 용기가 생긴다.
그렇지 않으면 "아 난 안되는가보다." 하고 다른 소스를 찾게 되는 자신을 바라보면서 언제까지 이러면 안되겠다는 생각을 했었다.
static void bitwiseTest4() {
  int seven = 7; // 0000 0111
  int nineteen = 19; // 0001 0011

  // & : and 연산
  // 0000 0111
  // 0001 0011
  // ---------
  // 0000 0011 ->  2 + 1 -> 3
  System.out.println(seven & nineteen);

  // | : or 연산
  // 0000 0111
  // 0001 0011
  // ---------
  // 0001 0111 -> 16 + ( 4 + 2 + 1 ) -> 23
  System.out.println(seven | nineteen);

  // ^ : xor 연산
  // 0000 0111
  // 0001 0011
  // ---------
  // 0001 0100 -> 16 + 4 -> 20
  System.out.println(seven ^ nineteen);

  // ~ : 보수(반전)
  // 0000 0111 -> 1111 1000 -> 1(부호) 111 0000 -> -128 + 64 + 32 + 16 + 8 ->
  System.out.println(-128 + 64 + 32 + 16 + 8);
  System.out.println(~seven);
}

output: 
3
23
20
-8
-8
이걸로 뭘 할 수 있을까? 그건 나중에 알아보기로 해야겠다. 일단 시프트 연산부터 정리를 해야겠다.
시프트 연산은 비트들을 왼쪽 오른쪽으로 움직이면서 노는 것이다. 처음에는 이게 뭐지 싶지만 익숙해지면 괜찮을 것이다. (아마 그럴 것이다. 나는 초보니까 익숙하지 않다.)
static void bitwiseTest5() {
  //시프트 연산
  int ten = 10; // 0000 1010
  int m_ten = -10; // 1
  System.out.println(Integer.toBinaryString(ten));
  System.out.println(Integer.toBinaryString(m_ten));
  // signed right shift : 오른쪽으로 한칸 이동 이전 맨 왼쪽의 숫자에 따라 새로 생성되는 숫자가 정해진다
  // ten : 0000 1010 -> 0000 0101 -> 5
  // m_ten : 1111 0110 -> 1111 1011 -> -1 - 4 = -5
  System.out.print((ten >> 1) + " " + (m_ten >> 1) + "\n");
  // unsigned right shift : 맨 왼쪽 숫자에 상관없이 0으로 통일한다
  // ten : 0000 1010 -> 0000 0101 -> 5
  // m_ten : 1111 1111 1111 1111 1111 1111 1111 0110 -> 0111 1111 1111 1111 1111 1111 1111 1011
  // -> 2147483647(Integer 최대값) - 4 -> 2147483643
  System.out.print((ten >>> 1) + " " + (m_ten >>> 1) + "\n");
  // left shift : 왼쪽으로 이동하는 것이다 right shift의 반대라고 생각하면 된다.
  // 여기서 주목해야 할 점은 right shift는 2배로 줄어들고 left shift는 2배로 커진다는 것이다.(이진수니까 당연한 것이겠지만)
  // 그래서 10번 움직인다면 2의 10승 1024가 곱해진다.
  System.out.print((ten << 10) + " " + (m_ten << 10) + "\n");
  System.out.println((ten << 1) + " " + (m_ten << 1) + "\n");
}

2017년 5월 9일 화요일

[java][design pattern]비지터패턴은 왜 쓰는 것일까? - 2

자 이제 비지터 패턴을 이용하면 무엇이 변하는지 공부하자.
  • Visitor가 Hair들을 방문할 수 있도록 VisitableHair 인터페이스를 만들자.
  • Hair들이 VisitableHair를 구현하도록 하자. (BoldHair, BushyHair, CurlyHair, HairyHair)
  • VisitableHair를 방문할 HairShopVisitor 인터페이스를 만들자.
  • 실제로 방문해서 일을 할 헤어디자이너들을 구현하자. (Barber, Hairdresser, Stylelist)
public interface VisitableHair {
  void accept(HairShopVisitor visitor);
  //아직 HairShopvisitor가 없어서 에러가 남
}
public class BoldHair implements VisitableHair {
  @Override
  public void accept(HairShopVisitor visitor) {
    System.out.println(this + " 아무렇게나 해주세요");
    visitor.visit(this);
  }
  @Override
  public String toString() {
    return "I have a bold Hair";
  }
} 

public class BushyHair implements VisitableHair {
  @Override
  public void accept(HairShopVisitor visitor) {
    System.out.println(this + " 아무렇게나 해주세요");
    visitor.visit(this);
  }
  @Override
  public String toString() {
    return "I have a bushy Hair";
  }
}

public class CurlyHair implements VisitableHair {
  @Override
  public void accept(HairShopVisitor visitor) {
    System.out.println(this + " 아무렇게나 해주세요");
    visitor.visit(this);
  }
  @Override
  public String toString() {
    return "I have a curly Hair";
  }
}
public class HairyHair implements VisitableHair {
  @Override
  public void accept(HairShopVisitor visitor) {
    System.out.println(this + " 아무렇게나 해주세요");
    visitor.visit(this);
  }
  @Override
  public String toString() {
    return "I have a Visitable Hair";
  }
}
이제 HairShopVisitor를 만들자.
public interface HairShopVisitor {
  void visit(BoldHair boldHair);
  void visit(BushyHair busyHair);
  void visit(CurlyHair curlyHair);
  void visit(HairyHair hairyHair);
}
HairShopVisitor를 구현해서 사용하려면 저 위에 있는 모든 객체를 구현 해놔사 사용할 수 있다.
일단 하나를 구현해보자.
public class HairShopBarberVisitor implements HairShopVisitor{
  @Override
  public void visit(BoldHair boldHair) {
    System.out.println("나는 이용사입니다. boldHair 군요. 면도해드릴게요\n");
  }
  @Override
  public void visit(BushyHair busyHair) {
    System.out.println("나는 이용사입니다. busyHair 군요. 밀어드릴게요\n");  
  }
  @Override
  public void visit(CurlyHair curlyHair) {
    System.out.println("나는 이용사입니다. curlyHair 군요. 밀어드릴게요\n");  
  }
  @Override
  public void visit(HairyHair hairyHair) {
    System.out.println("나는 이용사입니다. hairyHair 군요. 밀어드릴게요\n");  
  }
}
이렇게 하면 방문자로서 하나의 로직이 추가된 것이다. 2개를 마저 만들자.
public class HairShopHairdresserVisitor implements HairShopVisitor{
  @Override
  public void visit(BoldHair boldHair) {
    System.out.println("미용사입니다. boldHair 군요. 파마(?)해드릴게요\n");
  }
  @Override
  public void visit(BushyHair busyHair) {
    System.out.println("미용사입니다. busyHair 군요. 파마해드릴게요\n");
  }
  @Override
  public void visit(CurlyHair curlyHair) {
    System.out.println("미용사입니다. curlyHair 군요. 파마해드릴게요\n");
  }
  @Override
  public void visit(HairyHair hairyHair) {
    System.out.println("미용사입니다. hairyHair 군요. 파마해드릴게요\n");
  }
}

public class HairShopHairStylelistVisitor implements HairShopVisitor{
  @Override
  public void visit(BoldHair boldHair) {
    System.out.println("스타일리스트입니다. boldHair 군요. 스타일있게 해드릴게요\n");
  }
  @Override
  public void visit(BushyHair busyHair) {
    System.out.println("스타일리스트입니다. busyHair 군요. 스타일있게 해드릴게요\n");
  }
  @Override
  public void visit(CurlyHair curlyHair) {
    System.out.println("스타일리스트입니다. curlyHair 군요. 스타일있게 해드릴게요\n");
  }
  @Override
  public void visit(HairyHair hairyHair) {
    System.out.println("스타일리스트입니다. hairyHair 군요. 스타일있게 해드릴게요\n");
  }
}
이제 테스트를 해보자.
public static void main(String[] args) {
  VisitableHair[] variable_hair = { new BoldHair(), new BushyHair(), new CurlyHair(), new HairyHair()};
  HairShopVisitor[] artists = {new HairShopBarberVisitor(), new HairShopHairdresserVisitor(), new HairShopHairStylelistVisitor()};
  
  for(HairShopVisitor artist : artists) {
    for (VisitableHair hair : variable_hair )
      hair.accept(artist);
    }
  }
답은?
I have a bold Hair 아무렇게나 해주세요
나는 이용사입니다. boldHair 군요. 면도해드릴게요

I have a bushy Hair 아무렇게나 해주세요
나는 이용사입니다. busyHair 군요. 밀어드릴게요

I have a curly Hair 아무렇게나 해주세요
나는 이용사입니다. curlyHair 군요. 밀어드릴게요

I have a Visitable Hair 아무렇게나 해주세요
나는 이용사입니다. hairyHair 군요. 밀어드릴게요

I have a bold Hair 아무렇게나 해주세요
미용사입니다. boldHair 군요. 파마(?)해드릴게요

I have a bushy Hair 아무렇게나 해주세요
미용사입니다. busyHair 군요. 파마해드릴게요

I have a curly Hair 아무렇게나 해주세요
미용사입니다. curlyHair 군요. 파마해드릴게요

I have a Visitable Hair 아무렇게나 해주세요
미용사입니다. hairyHair 군요. 파마해드릴게요

I have a bold Hair 아무렇게나 해주세요
스타일리스트입니다. boldHair 군요. 스타일있게 해드릴게요

I have a bushy Hair 아무렇게나 해주세요
스타일리스트입니다. busyHair 군요. 스타일있게 해드릴게요

I have a curly Hair 아무렇게나 해주세요
스타일리스트입니다. curlyHair 군요. 스타일있게 해드릴게요

I have a Visitable Hair 아무렇게나 해주세요
스타일리스트입니다. hairyHair 군요. 스타일있게 해드릴게요
몇 번 더 만들어보면 손에 익지 않을까 싶다.

[java][design pattern]비지터패턴은 왜 쓰는 것일까? - 1

비지터 패턴을 쓰는 이유가 뭘까?
왜 방문을 해서 로직을 추가하는 걸까? 그냥 해당 클래스에 로직을 넣어서 쓰면 안될까?
해당 클래스를 바꾸지 못할 때 쓰는 것일까? 해당 클래스들의 자료구조는 변화하지 않을 것이고 로직은 계속 추가될 것이라면 비지터가 좋을 것 같기도 하다.
여기 머리를 자르기로 하자.
곱슬, 직모, 탈모, 대머리, 금발의 긴머리, 뽀글뽀글 등등 여러가지의 머리가 있다. 이들은 모두 미용실에가서 이렇게 말한다.
어울리게 잘라주세요
이제 미용사 성향 / 머릿카락에 따라 머리를 자를 것이다. 구현은
  1. Hair, HairShop 인터페이스 생성
  2. 각 인터페이스의 구현체 생성(BoldHair, BushyHair / Barber, Hairdresser)
  3. 그리고 테스트
// 1. 인터페이스 생성
public interface Hair { }
public interface HairShop {
  void cut(BoldHair boldHair);
  void cut(BushyHair busyHair);
  void cut(Hair hair);
}
이제 인터페이스를 구현하자.
// 2. 구현체 생성
public class BoldHair implements Hair{ }
public class BushyHair implements Hair{ }

public class Barber implements HairShop {
  @Override
  public void cut(BoldHair boldHair) {
    System.out.println("Barber : boldHair");
  }
  @Override
  public void cut(BushyHair busyHair) {
    System.out.println("Barber : BusyHair");
  }
  @Override
  public void cut(Hair hair) {
    System.out.println("Barber : Hair Interface... ");
  }
}

public class Hairdresser implements HairShop{

  @Override
  public void cut(BoldHair boldHair) {
    System.out.println("Hairdressor : BoldHair");
  }

  @Override
  public void cut(BushyHair busyHair) {
    System.out.println("Hairdressor : BushyHair");
  }

  @Override
  public void cut(Hair hair) {
    System.out.println("Hairdressor : Hair Interface... ");
  }
}
이제 테스트를 해보자.
public class Test {
  public static void main(String[] args) {
    Hair[] hairs = {new BoldHair(), new BushyHair()};
    HairShop[] artists = {new Barber(), new Hairdresser()};
 
    for (Hair hair : hairs)
      for (HairShop artist : artists)
        artist.cut(hair);
  }
}
콘솔을 확인
Barber : Hair Interface... 
Hairdressor : Hair Interface... 
Barber : Hair Interface... 
Hairdressor : Hair Interface...  
이렇게 된다. 결국 머릿카락의 정보는 가질 수 없다. 왜냐하면 자바는 싱글디스패치이기 때문인데 자세한 내용은 더블디스패치관련 글을 읽어보기를 바라면서...
여하튼 비지터패턴은 해당 클래스를 변경하지 않고 Visitor들을 추가해서 일을 할 수 있게 한다.
Visitor만 새로 만들면 hair들은 새로운 로직을 추가하지 않고 로직을 추가할 수 있게 된다.
출처:
https://dzone.com/articles/design-patterns-visitor https://sourcemaking.com/design_patterns/visitor/java/1 https://www.tutorialspoint.com/design_pattern/visitor_pattern.htm

2017년 5월 5일 금요일

[java] CSVWriter사용하기 (그리고 쌍따옴표 없애기)

CSV는 참으로 많은 곳에서 사용한다. 데이터를 저장할 때 사용하는 아주 기본적인 포맷이 아닌가 싶다.
CSV에서 오는 간결함은 그것을 만드는 사람마저 간결함을 추구하게 하는 힘이 있다.
콤마으로 나눠진 값들(CSV, Comma Separated Values)은 그 간결함 속에서 더욱 확장되어왔다.

자바에서는 CSV를 만들기 위한 Writer를 따로 만들어주고 있지 않지만, 사람들이 애용하는 라이브러리는 존재한다.
그중 하나 opencsv을 사용해보자.
/** CSVWriter 사용해보기**/
public class CSVTest {
  static List makeFileValues() {
    List list = new ArrayList();
    for(int i = 0; i < 10 ; i++) {
      list.add(new String[] { String.valueOf(i), String.valueOf(i+i), String.valueOf(i+i+i)});
    }
    return  list;
  }
}
실행해보자.
public static void main(String[] args) throws IOException {
  String Path = "C:/ynam/";
  String Name = "CSVTEST";
  
  try (CSVWriter writer = new CSVWriter(new FileWriter(Path+Name + ".csv"))){
    writer.writeAll(makeFileValues());
  }
}
실행해보자.
"0","0","0"
"1","2","3"
"2","4","6"
"3","6","9"
"4","8","12"
"5","10","15"
"6","12","18"
"7","14","21"
"8","16","24"
"9","18","27"
이렇게 나왔다.
이 현상은 사실 우리 회사에서 벌어지던 일이었다. 이 따옴표가 문제는 아니다. 하지만 이 내용을 그대로 다시 디비에 넣고 다시 빼낸다면?
"""0""","""0""","""0"""
"""1""","""2""","""3"""
"""2""","""4""","""6"""
"""3""","""6""","""9"""
"""4""","""8""","""12"""
"""5""","""10""","""15"""
"""6""","""12""","""18"""
"""7""","""14""","""21"""
"""8""","""16""","""24"""
"""9""","""18""","""27"""
처음부터 우리가 원하는 그 값 자체만을 담고 싶다면? 생성자에 추가하나만 하면 된다.
CSVWriter writer = new CSVWriter(new FileWriter(Path+Name + ".csv"))
여기를
CSVWriter writer = new CSVWriter(new FileWriter(Path+Name + ".csv"), ',', CSVWriter.NO_QUOTE_CHARACTER)
이렇게 바꾸고 다시 해보자.
  public static void main(String[] args) throws IOException {
    String Path = "C:/ynam/";
    String Name = "CSVTEST_without_qoute";
  
    try (CSVWriter writer = new CSVWriter(new FileWriter(Path+Name + ".csv"), ',', CSVWriter.NO_QUOTE_CHARACTER)){
      writer.writeAll(makeFileValues());
    }
}
자 실행해보면 어떻게 나올까
0,0,0
1,2,3
2,4,6
3,6,9
4,8,12
5,10,15
6,12,18
7,14,21
8,16,24
9,18,27
단순하다.

2017년 4월 23일 일요일

[java] List에서 int[] 로 바꾸는 방법 (on java8)

List에서 int[]로 바꾸는 손쉬운 방법은 없었다. Arrays의 toArray()는 Object[]를 반환하기 때문에 불가능했고
toArray(T[] ...) 얘도 primitive type인 int[]를 담을 순 없었다.

하지만 Java8에서는 쉽게 변환할 수 있다.
List list = new ArrayList<>();
...
int[] i_arr = list.stream().mapToInt(i -> i).toArray();
어떻게 이렇게 쉽게 되는 걸까?
list.stream()은 게다가 아직 Integer이다. 무슨 일이 벌어진 걸까?
java8부터 primitive type을 다룰 수 있는 IntStream이라는 것이 있다.
우리는 이놈으로 바꿔야만 한다. 그래서 사용하는 것이 mapToInt이다 얘는 IntStream을 리턴한다.
mapToInt이라는 이름처럼 요소 하나하나를 매개변수 안에 있는 로직대로 이행한 후 IntStream으로 리턴하는 듯하다.

그래서 실제로는 이렇게 되야 한다.
mapToInt((Integer i) -> i.intValue()) or mapToInt(Integer::intValue())
Integer에 있는 메소드 intValue로 int로 변환하는 함수를 넣는 것이 정상이다. 그런데 왜 그냥 아무짓도 안해도 에러가 안나고 잘 되는 걸까?
바로 언박싱을 이용하는 것인데, 리턴값은 int로 정해져있고 컴파일러가 그걸 확인할 것이다.

만약 자바8을 쓸 수 없다면?
Guava를 사용하면 되겠다.

[java][design pattern] 더블 디스패치 패턴은 언제 쓰일까?

더블디스패치 패턴은 대체 왜 쓰이는 걸까?
자바는 싱글디스패치만을 지원한다고 한다.
그 말은 더블디스패치를 사용하려면 패턴으로 메꿔야 한다는 말인가보다.
예전에는 싱글디스패치만으로도 만족하고 살았지만 다른 많은 언어들이 실행시키는 인스턴스와 매개변수 둘 다 타입체크를 하여 멋져졌다 하니.
우리도 패턴으로 그것이 가능함을 보여야 하지 않겠나 해서 만들어 진 것이 아닌가 하는 상상을 해본다.

일단 만들어보자. 이제부터 할 일은 이렇게 된다.
  • 인터페이스 둘을 만든다. (Format, Post)
  • 인터페이스를 구현한다. (Post - Mail,SMS / Format - JPG,XML)
  • 이 두 인터페이스를 연결한다.
  • 실행해본다.
  • 일단 왜 더블디스패치가 없이 만들면 어떻게 되는지 보자.
    1. 인터페이스 둘을 만든다.
    interface Format {}
    interface Post {}
    
    2. 인터페리스를 구현한다. (총 4개)
    public class JPG implements Format { }
    public class XML implements Format { }
    
    public class Mail implements Post { }
    public class SMS implements Post { }
    
    이제 인터페이스에 필요한 내용들 추가하고 구현도 해서 이 두 인터페이스를 연결하자.
    Post인터페이스는 JPG / XML에 따라 보내는 방식이 다를 수 있다. 그래서 그 타입에 따라 다른 일을 하도록하자.
    public interface Post {
      void send(Format format);
      void send(JPG jpg);
      void send(XML xml);
    }
    
    게다가 SMS/MAIL에 따라 다를 것이다.
    public class Mail implements Post {
    
      @Override
      public void send(Format format) {
        throw new RuntimeException("Mail.send(Format format) :: 타입을 알 수 없습니다.");
      }
    
      @Override
      public void send(JPG jpg) {
        System.out.println("Mail.send(JPG jpg)");
      }
    
      @Override
      public void send(XML xml) {
        System.out.println("Mail.send(XML xml)");
      }
    
    }
    
    public class SMS implements Post {
    
      @Override
      public void send(Format format) {
        throw new RuntimeException("SMS.send(Format format) :: 타입을 알 수 없습니다.");
      }
    
      @Override
      public void send(JPG jpg) {
        System.out.println("SMS.send(JPG jpg)");
      }
    
      @Override
      public void send(XML xml) {
        System.out.println("SMS.send(XML xml)");
      }
    
    }
    
    다 되었다. 실행해보자.
    public class Test {
      public static void main(String[] args) {
        Post post = new Mail();
        Format format = new JPG();
        post.send(new JPG());
        post.send(format);
      }
    }
    
    잘 될까?
    Mail.send(JPG jpg)
    Exception in thread "main" java.lang.RuntimeException: Mail.send(Format format) :: 타입을 알 수 없습니다.
     at designpattern.doubledispatch.post.Mail.send(Mail.java:11)
     at designpattern.doubledispatch.Test.main(Test.java:13)
    
    하나는 잘 되었고, 다른 하나는 잘 되지 않았다. 왜냐하면 메소드 오버로딩은 정적 디스패치(static dispatch)를 한다. 이 말은 런타임에 타입을 동적으로 체크하는 것이 아니라 미리 컴파일 이전에 타입을 미리 제대로 정해 놔야 한다는 말이다.
    에러가 난 곳은 정확한 타입(JPG)를 넣은 것이 아니라. Format이라는 인터페이스를 넣었다. 이것이 문제가 되는 것
    그러면 어떻게 해야 할까?
    일단 자바에서는 매개변수 타입체크를 동적으로 하지않는다고 하니까 타입체크를 두 번 하도록 해보자.
    지금부터 할일은
    1. Post 인터페이스를 매개변수가 Format인 것만 남기고 삭제한다. (어짜피 이걸로 타입체크를 못함)
    2. Format 인터페이스에 Mail,SMS(Post의 구현체 전부)를 각각 매개변수로 하여 void send(T t)형식의 메소드를 추가한다
    3. Post의 구현체에서 해당 메소드를 호출한다.
    4. 실제로 로직을 실행하는 곳은 Format의 구현체들에서 각각 구현한다.
    말이 잘 전달되지 않은 것 같은데 일단 코드를 한 번 짜보자.
    // 1. 매개변수가 Format 인것 빼고 다 삭제
    public interface Post {
      void send(Format format);
    }
    // 2. Mail,SMS를 각각 매개변수로 send라는 메소드를 추가
    public interface Format {
      /*
       * 여기에서 타입체크를 하는 것이다. 원래는 Post에서 했지만
       * 한 번 더 하기 위해, Format에서 한다.
       * 
       */
      void send(Mail mail);
      void send(SMS sms);
    }
    
    이제 인터페이스를 바꿨으니 구현체들을 바꿔보자.
    // 3. 새로 만든 메소드 호출
    public class Mail implements Post {
    
      @Override
      public void send(Format format) {
        format.send(this); // 여기서 이미 this는 타입체킹이 되어있음.
      }
    }
    
    public class SMS implements Post {
    
      @Override
      public void send(Format format) {
        format.send(this);
      }
    
    }
    
    이제 실제 로직이 들어있는 곳을 보자.
    // 4. 실제 로직이 있는 곳 변경
    public class JPG implements Format {
    
      @Override
      public void send(Mail mail) {
        System.out.println("mail send JPG");
      }
    
      @Override
      public void send(SMS sms) {
        System.out.println("SMS send JPG");
      }
    
    }
    
    public class XML implements Format {
    
      @Override
      public void send(Mail mail) {
        System.out.println("mail send XML");
      }
    
      @Override
      public void send(SMS sms) {
        System.out.println("SMS send XML");
      }
    
    }
    
    한번 실행해보자.
    public class Test {
      public static void main(String[] args) {
        Post post = new Mail();
        Format format = new JPG();
        post.send(new JPG());
        post.send(format);
      }
    }
    
    과연 결과는??
    mail send JPG
    mail send JPG
    
    성공이다. 이 패턴은 비지터 패턴과 아주 유사하다고 하는데, 비지터 패턴은 내 생각에는 클래스를 변경하지 않고 새로운 로직을 추가하기 위해 필요한 패턴인 것 같고
    더블디스패치패턴은 좀 더 일반적인 기술같다. 양쪽의 타입을 제대로 체크하기 위해 만든 기술인듯하다.

    [java] interface constant는 왜 쓰면 안될까?

    가끔 이런 생각을 해보기도 한다.
    귀찮은데 그냥 상수도 인터페이스로 넣어서 쓰면 안되나?
    아니면 implements로 상수를 전부 가져와서 이름만으로 써도 되지 않을까?
    아래의 예시가 왜 쓰면 안되는지 도움이 될 것 같다. 우선 클래스 안에 있는 상수들을 보자.
    public class ClassCons {
     public static final double CONS = 0.0;
     public static final String CONS1 = "22";
     public static final int CONS2 = 1;
    }
    
    이제 이것들을 인터페이스 상수로 바꿔보자.
    interface InterCons {
     double CONS = 0.0;
     String CONS1 = "22";
     int CONS2 = 1;
    }
    
    인터페이스는 어짜피 public이다. 그러니 public이 필요없다. 바뀌지 않을 것이니 final도 필요없다.
    마치 짧아진 코드를 보며 내가 뭔가 해낸(?)사람 처럼 느낄 수도 있지만 아님을 바로 깨달을 수 있다.
    public class BadIdea implements InterCons{
     public BadIdea() {
      System.out.println(CONS);
      System.out.println(CONS1);
      System.out.println(CONS2);
     }
     public static void main(String[] args) {
      BadIdea badIdea = new BadIdea();
     }
    }
    
    이 내용은 위에서 만든 인터페이스 상수를 가져온 것이다. 과연 이렇게 하면 잘 될까?
    0.0
    22
    1
    
    예상한 대로 나왔다. 하지만 이렇게 한다면?
    public class BadIdea implements InterCons{
     private int CONS = 100;
     public BadIdea() {
      System.out.println(CONS);
      System.out.println(CONS1);
      System.out.println(CONS2);
     }
     public static void main(String[] args) {
      BadIdea badIdea = new BadIdea();
     }
    }
    
    다시 실행해보자.
    100
    22
    1
    
    값이 바뀌어 있다. 이 말은 인터페이스 상수를 가져오는 순간 해당 클래스와 그 서브 클래스들이 상수들로 더러워(?)진다는 것을 말한다.
    자칫하면 값들이 꼬일 수 있다. 에러도 잘 보이지 않을 거고 디버깅에도 애를 먹을 수도 있겠다.

    2017년 4월 20일 목요일

    [java] volatile이란 뭘까?

    Dzone에서 volatile내용을 보고 있다가 좀 적어놔야 할 것같아서 적는다.
    자바의 keyword 중에 하나인 volatile은 대체 정확히 어떨 때 쓰는 것일까?
    애초에 volatile은 뭘까?
    volatile은 휘발성 이란 의미를 가지고 있다. 잘 날아간다는 말이니까. 금방금방 그 값이 사라진다고 말 할수도 있고, 그 값이 의미없어진다고도 말 할수 있겠다.
    volatile은 값을 읽고, 쓰는 것에 대한 원자성(Atomic)을 유지해주는 것 같다.

    왜 이게 필요한가 하면 멀티스레드 환경에서 스레드 각각이 변수들의 값을 캐싱해서 사용한다는 것때문이다. 덕분에 값을 조회할 때마다 실제 값을 조회할 필요가 없이 사용할 수 있지만 만약 공유하는 값이 있고 그 값이 자주 변한다면 문제가 생길 수 있지 않을까?
    그때 volatile을 사용하면 되지 않을까 싶다.
    
    public class VolatileTest {
      private static volatile int count = 0;
    //private static int count = 0;
      public static void main(String[] args) {
        new IwillGetIt().start();
        new IwillChangeIt().start();
      }  
      
      static class IwillGetIt extends Thread {
        @Override
        public void run() {
          int my_local = count;
          while (my_local < 5) {
            if (my_local != count){
              System.out.println("바꼈다!!! : " + count);
       my_local = count;
     }
          }
        }
      } 
      static class IwillChangeIt extends Thread {
        @Override
        public void run() {
          int my_local = count;
          while (my_local < 5 ) {
            System.out.println("값을 증가 시킴 : " + (++my_local));
            count = my_local;
            try {
              Thread.sleep(2000);
            } catch (InterruptedException e) {
       e.printStackTrace();
     }
          }
        }
      }
    }
    
    어떻게 될까? 위의 내용은 volatile을 넣은 것이다. count라는 값은 두개의 스레드가 공유를 한다. 서로 IwiilChangeIt은 바꾸는 아이고 IwillGetIt은 바꾸는 현장을 포착하는 아이다.
    값을 증가 시킴 : 1
    바꼈다!!! : 1
    값을 증가 시킴 : 2
    바꼈다!!! : 2
    값을 증가 시킴 : 3
    바꼈다!!! : 3
    값을 증가 시킴 : 4
    바꼈다!!! : 4
    값을 증가 시킴 : 5
    바꼈다!!! : 5
    
    그렇다면 이 상태에서 저 위에 volatile이 없는 녀석의 주석을 풀고, volatile이 있는 녀석은 주석을 걸어보고 다시 실행하자.
    값을 증가 시킴 : 1
    바꼈다!!! : 1
    값을 증가 시킴 : 2
    값을 증가 시킴 : 3
    값을 증가 시킴 : 4
    값을 증가 시킴 : 5
    
    그렇다면 volatile은 항상 쓰는 것이 스마트한 것일까?
    난 잘 모르겠지만 그렇게는 쓰지 않는 것이 좋을 것 같다. 왜냐하면?
    1. volatile은 변수에게 특권을 주는 것과 같다. 그 특권을 남발하면 안된다.
    2. volatile을 모든 변수에게 주면 코드가 지저분하다.
    3. 1번과 일맥상통한 것인데 volatile을 죄다 쓰면 누가 진짜 필요한 volatile인지 누가 알 수 있을까. 왜 이렇게 썼는지 고민하고 있지 않을까?
    4. 성능의 이슈는 없을까? 하지만 이건 아직 내가 신경쓸 것은 아닌 듯 하다.

    2017년 4월 13일 목요일

    [JavaScript] 자바스크립트에서 private변수 사용하기

    자바스크립트에서는 private을 넣는다고 private 변수가 되지 않는다.
    var my obj = {
      myprop: 1,
      getProp: function() { return this.prop; }
    }
    console.log(myobj.myprop);
    1
    console.log(myobj.getProp()); 
    1
    
    다른 방법으로도 한번 만들어보자.
    function G() {
      this.name '지';
      this.age = function() { return 1; }
    }
    var g = new G();
    console.log(g.name);
    '지'
    console.log(g.age());
    1
    

    Solution

    자바스크립트는 별도의 syntax가 없어도 private변수를 만들 수 있다.
    function new_G() {
      var name = 'G의 숨은 뜻은 지메일'; // private
      this.getName = function() { return name; };
    }
    var secret_g = new new_G();
    console.log(secret_g.name);
    undefined
    console.log(secret_g.getName());
    'G의 숨은 뜻은 지메일'
    
    생성자가 함수의 클로저를 만들고 그 클로저 스코프 안에 속하는 변수들을 만든다. closure scope는 생성자 외부로 노출되지 않는다.

    2017년 4월 12일 수요일

    [java][thread] join을 이용하여 thread가 끝났는지 확인하기

    join()을 이용하여 thread가 끝났는지 확인하자.

    오늘 이런 형태의 소스를 보았다. (아래 내용은 예시)
    RunnableClass01 rc01 = new RunnableClass01();
    RunnableClass02 rc02 = new RunnableClass02();
    RunnableClass03 rc03 = new RunnableClass03();
    
    Thread th01 = new Thread(rc01);
    Thread th02 = new Thread(rc02);
    Thread th03 = new Thread(rc03);
    
    th01.start();
    th02.start();
    th03.start();
    
    DB.updateThreadEndsTime(); // 이것이 문제
    
    대충 이런식이었는데... 쓰레드는 끝나지도 않았지만 시작하자마자 스레드가 끝났다는 로직을 실행시킨다.
    전체 소스를 보지 않은 나의 탓이 크지만
    쓰레드가 완료되었다는 시간을 처리하는 로직은 '당연히' 쓰레드가 전부 끝났을 때 업데이트 할 것이라는 가정이 있었기에 로직 수정 후 낭패를 보았다.
    그 후 나는 동료에게 물었다.
    "왜 이렇게 해야 하죠? 쓰레드가 끝나고 완료 업데이트를 하면 안되나요?"
    "쓰레드는 원래 그래요. 서로 독립적으로 실행되기 때문이죠."
    나는 단순하게 join()을 사용해서 그것이 가능함을 보이려 했다.
    RunnableClass01 rc01 = new RunnableClass01();
    RunnableClass02 rc02 = new RunnableClass01();
    RunnableClass03 rc03 = new RunnableClass01();
    
    Thread th01 = new Thread(rc01);
    Thread th02 = new Thread(rc02);
    Thread th03 = new Thread(rc03);
    
    th01.start();
    th02.start();
    th03.start();
    
    try {
      th01.join();
      th02.join();
      th03.join();
    }catch (Exception e) { }
    
    DB.updateThreadEndsTime(); // 이제 스레드 전부 완료되면 된다.
    
    "이러면 쓰레드 하나가 끝나면 다른 하나가 시작되는 것 아녜요?"
    나는 말했다.
    "아닙니다. 시작은 같이 하고 끝나는 것만 동기되는 거예요.
    어짜피 다 끝나야 완료처리 되야 하는 거니까 다 끝나야 일을 하는것이 맞다고 생각해요." 이렇게 끝났다. 하지만 여기서 하나 더 수정을 해야겠다.
    Thread th01 = new Thread(new RunnableClass01());
    Thread th02 = new Thread(new RunnableClass02());
    Thread th03 = new Thread(new RunnableClass03());
    
    th01.start();
    th02.start();
    th03.start();
    
    try {
      th01.join();
      th02.join();
      th03.join();
    } catch (Exception e) { }
    
    DB.updateThreadEndsTime(); // 이제 스레드 전부 완료되면 된다.
    
    물론 다른 방법도 많겠지만, 실력의 부족과 상황이 여의치 않아 이렇게 단순하게 바꾸는 것 만으로도
    로직의 큰 변화가 왔다.
    join(), wait(), notify() 같은 것은 기본적으로 알아야할 기능 같다.

    2017년 3월 28일 화요일

    [시간의향기]를 읽고

    전작 [피로사회]를 수년 전에 읽었었다. 대학교 시절 독서토론을 하면서 이 강렬한 내용을 보면서 모두가 놀랬었다. 아주 짧은 글인데 한 장 한 장 넘기는 종이가 무겁다. 들어 올리다가도 이내 내리고 다시 읽는다. 글 자체에 대한 이해가 힘들었다. 원래 책을 읽으면서 이해가 안되면 책 탓을 하지만, 이 책은 나의 탓이라는 주문을 걸면서 인터넷으로 단어들을 검색하며 읽고 또 읽었다.

    그 후 한병철이라는 철학가의 다른 책을 꼭 읽기로 했었는데, 이제야 [시간의 향기]라는 책을 구매했다. 역시나 시집보다 작은 책임에도 내 마음은 '언제 이 다 읽나' 하는 무거운 마음이 들었다. 한 장 넘기다가 다시 돌아오고, 한 문장 한 문장 곱씹다가 책을 완독했지만, 작가가 말하는 세계관을 완벽하게 이해하지 못했다. 분명 나의 부족함이라 생각하기에 나중에 좀 더 시간이 지나서 다시 읽기로 하며 책을 덮었다.

    [시간의 향기] 내용

    세상은 너무 빨라서 이제는 역사가 만들어지지 않고 있다. 세상이 너무 빠르게 나아가기 때문에 우리는 따라잡기 바쁘다. 우리는 숨이 턱밑까지 차오르게 하는 속도 때문에 시간의 향기를 맡을 수 없다.

    느리게 걷기나 느린 삶을 추구하려는 것, 이런 것들은 이 빠른 세상 속에서 살아남기 위한 치료법이 아닌 증상일 뿐이다. 우리는 빠르게 나아가는 시간을 잡을 방법이 없는 것 같다. 시간은 적당히 느려야 세상에 그 발자취가 새겨지고 우리는 그것을 기억하게 되고 되짚고 반성하고 진화한다. 그리고 세상이 빨라졌다고 우리 인생이 편해진 것은 아니다. 이것이 우리 마음의 조급함을 대신해주지 않는다. 우리는 그 속도를 따라잡으려 애쓰고, 그 위에 올라타 더 조급해진다.

    우리가 가는 길의 향기, 시간의 향기를 맡을 세도 없이 우리는 이곳저곳으로 갈 뿐이다. 우리는 멈춰야 하며, 아무것도 하지 않음으로 바로 보아야 한다. 그리고 사색해야 한다.
    노동은 자유롭게 만들지 않는다. 일의 명령은 새로운 노예사회를 낳는다.

    노동을 멈추고 사색하는 삶은 가지자.

    2017년 3월 22일 수요일

    [타르튀프]를 읽고

    열린책들 세계문학서적 중에 아주 특이한 이름의 책을 보았다. [타르튀프]라는 글인데 이 책이 나를 이끈 이유는 머리말을 읽고 나서였다. 글쓴이 몰리에르는 신에 대한 내용도 과감히 희극의 소재로 사용해왔는데, 권력자들을 소재로 사용할 때부터, 그의 서적이 불온서적이 되며, 무대에 올릴 수 없는 등 갖가지 제약을 받게 된다. 머리말에는 그들에 대한 작가의 절제된 분노를 느낄 수 있는데, 그것은 권력자들을 향한 질타였다.
     

    [타르튀프]는 이 책에 실려있는 세 편의 희극 중 하나이다. 아주 옛날에 쓴 희극임에도 호흡이 현대와 맞다. 아주 빠르다 못해 가파른 느낌이 준다.분명 그 당시에는 쉴세 없이 웃다보니 막이 내려오는 느낌이 있었으리라.
    권력자들은 자신들의 악행을 비난하는 것은 참지만
    놀림감이 되는 것은 참지 못한다.
    이 바로 위에 있는 글은 [타르튀프]의 머리말에 나오는 문장 중 하나이다. 희극의 중요성은 웃음 속에 감춰진 무엇이라는 것. 웃음으로 밖에 해소할 수 없는 그 무엇을 아주 잘 다룬 작품이었다. 특히 귀족들의 위선된 행동을 풍자한 [타르튀프]라는 희극은 참으로 많은 생각을 하게 해준다.



    권력자에게 칼을 휘두를 수 없지만, 그들을 깍아 내릴 수는 있다.
    그들을 저 위에 있지 않으며, 우리와 같은 사람이고, 때론 우리보다 아래 있다. 그들이 가진 권능, 신의 축복은 그들이 대단해서가 아니며, 사실 그들이 가진 권능은 신이 준 것이 아닌 우리의 두려움과 그들의 힘에서 나온다. 그들을 희극으로 놀림감으로 만들어 우리 앞에 세우고 심판하도록 하자.


    내가 느낀 감상이다. 하지만 몰리에르는 지속적인 압박에 지쳤는지 [타르튀프]의 마지막 희극 [인간 혐오자]에 그의 안타까움, 외로움이 느껴진다.