2011년 2월 10일 목요일

clone( ) 방식 - 깊은 복사/ 얕은 복사- deep copy shallow copy

사실 예전의 자바가 속도가 좋지 않았다는 사실은 누구나 공감하는 사실이다. Hotspot VM 이 나온 이유역시 이러한 데에서 비롯되었고..

자바가 느린 이유중에 하나는 역시 객체 생성이다. 메모리에 새로운 공간을 할당하고 거기에 데이터를 넣는 방식의 처리는 OOP에서는 피해갈 수 없지만 또한 이때문에 발생하는 성능의 저하는 어쩔 수 없다.

결국 OOP는 속도를 개선하기 위해서 다양한 방법을 시도했는데.. 대표적인 것들이 바로 pooling, caching기법, clone기법이라고 할 수 있다.

Cloneable 인터페이스를 이용하면 우리는 객체를 손쉽게 복사할 수 있다. 객체 생성을 해서 넣는 과정을 생략하고도 원본에 대한 또 다른 객체를 만들 수 있다. clone의 스펙을 보면 equals()가 반드시 true여야 한다는 보장은 하지 않아도 되기 때문에 복사본 객체가 아니라 데이터의 카피로도 사용할 수 있다는 얘기이다.

Shallow Copy

간단히 말하면 객체를 복사하는데 그 안의 내용물 마저 복사하지는 않는다는 얘기이다.

public class Origin implements Cloneable
{

 private String id;

 private String pw;

 private SubOrigin sub;

 ...

위와 같은 객체를 복사한다고 가정하자.

  Origin origin = new Origin();


  Origin cloneObj = (Origin) origin.clone();


위의 객체를 System.out.println()으로 보면 두 객체는 다른 주소값을 사용한다. 하지만 문제는 SubOrigin 에 있다.

ShallowCopy는 특정 객체를 복사할 때 피상적인 복사만 하게 된다.

ShallowCopy는 복사본 객체안에 있는 sub의 주소값이 원복 객체의 sub의 주소값과 동일하게 나온다.

이렇게 표면만 복사하는 것을 Shallow Copy라 하고, sub와 같은 하위 객체마저도 복사하는 방식을 deep copy라고 한다.


 protected Object clone(){
  try {
   //shallow copy
   //return super.clone();
   Origin cloneObj = (Origin)super.clone();
   cloneObj.setSub((SubOrigin)this.sub.clone());
  
   return cloneObj;
  
  } catch (CloneNotSupportedException e) {
   e.printStackTrace();
  }
  return null;
 }


위에 있는 소스를 보면 현재 객체의 복사본을 만든후에 하위 객체의 복사본을 만들어 주입하는 방식으로 작성한다.

2011년 2월 5일 토요일

Android에서 Context의 개념

 사실 Android쪽 프로그램을 만들다 보면 계속해서 이 Context라는 용어에 마주하게 됩니다. Context라는 클래스가 존재하기도 하고, Context라는 용어가 존재하기도 하기 때문에 여러분이 개념을 잡는 수준에 설명해 볼까 합니다.
개인적으로 Android를 공부하기 전에 Web Programming이나 Framework들을 공부할 필요가 있다고 생각하는데, 그 이유 중에 하나가 바로 이 Context라는 개념 때문입니다. 아니면 운영체제를 공부해 보신 분들에게는 Context라는 개념이 그리 낯선 개념은 아닙니다.

 Context를 한국말로 번역하자면 '문맥'이라는 우스운 말이 됩니다만, 디자인 패턴과 같은 곳에서는 '상황, 정황'이라는 말로도 사용됩니다. 하지만 좀 더 쉬운 개념으로 설명하자면 개인적으로 '울타리'라는 표현이 가장 좋다고 생각합니다. 즉 어떤 객체 n개가 동일한 Context에 놓여 있다는 것은 다른 표현으로는 'n개의 객체가 동일한 실행 환경에 있다'는 것을 의미합니다.

 예를 들어 static 변수를 생각해 봅니다.  static 변수(클래스변수)를 사용한다는 것은 현재 JVM내의 모든 객체가 동일한 값을 사용하게 됩니다. 반면에 여러 객체가 두 개의 Context내에 있다는 것을 그림으로 표현하면 아래의 그림처럼 됩니다.



따라서 어떤 객체가 어느 Context에 놓여 있느냐에 따라서 사용하는 값이 달라지게 됩니다.       
 Android의 경우는 거의 모든 객체를 단일한 Singleton객체로 관리합니다. 만일 다른 프로세스나 App에 의해서 특정한 데이터가 계속해서 변경된다면 이 때문에 App이 실행 도중에 원치 않는 결과를 만들어 낼 수 있습니다. 따라서 현재 App이 실행되는 하나의 '울타리'가 필요하게 되는데 이런 존재를 Context라고 합니다. Android에서는 코드를 물려주는 상속을 주로 사용하기 때문에 모든 Activity들은 자신이 어떠한 Context에서 동작해야 하는지를 알 필요가 있습니다.

2011년 2월 1일 화요일

간단한 디자인패턴-Command패턴

음.. 한 6년전에 정리하면서 만든 자료지만..
정리차 올립니다.

Command 패턴
Command 패턴은 인터페이스를 이용해서 내부에서 실행되는 객체가 무언지 모르는 상태에서
동일한 과정으로 메쏘드를 수행하고 싶을 때 사용하는 패턴이다.



다음과 같은 경우를 생각해 보자.
. Escm에서 여러개의 매니저가 존재한다.

. 각 매니저는 자신이 수행하기에 적합한 메쏘드가 있다.
. 매니저에게 동작을 시키고자 할 때 통일성을 갖게 하고자 하고 싶다.
예를 들어 파라미터의 값에 따라 자동적으로 특정 객체를 찾아내는 로직을 분리하고
특정 객체의 메쏘드는 인터페이스를 구현하도록 하면 다음과 같은 장점이 생길 수 있다.
. 어떤 객체이건간에 동일한 메쏘드 호출하면 된다.
. 새로운 객체를 추가할 때에도 인터페이스에 맞게 구현해 주면 된다.
이를 위해서 개발자가 먼저 해야 하는 것은 단 하나이다.

****인터페이스에서 코딩을 시작하라 *****
-----------------------------------------------------
Processable
-----------------------------------------------------
package command;
public interface Processable {

 public Object process()throws Exception;
}
-----------------------------------------------------
DocManager
-----------------------------------------------------
package command;
public class DocManager implements Processable {
 public Object process() throws Exception {
  System.out.println("DocManager의 처리 ");

  return null;
 }
}
-----------------------------------------------------
PodManager
-----------------------------------------------------
package command;
public class PodManager implements Processable {
 public Object process() throws Exception {
  System.out.println("PodManager의 처리 ");
  return null;
 }
}

-----------------------------------------------------
CommandTest
-----------------------------------------------------
package command;
public class CommandTest {

 Processable process = null;
 public static void main(String[] args) {

  CommandTest ct = new CommandTest();
  if(args.length < 1){
   System.out.println("args is null");
   return;
  }
  ct.test(args[0]);
 }
 private void test(String param) {

  Executor executor = new Executor();

  if(param.equals("1") == true ){
   process = new DocManager();
  }else{
   process = new PodManager();
  }

  executor.doJob(process);
 }
}
-----------------------------------------------------
Executor
-----------------------------------------------------
package command;
public class Executor {
 Processable command = null;

 public void doJob(Processable command){
  this.command = command;

  try{
   Object result = command.process();
 
  }catch(Exception e){
   e.printStackTrace();
  }
 }
}
디자인 패턴의 원칙이 '구현이 아니라 구성이다'이라는 원칙대로 인터페이스를 설계하고
인터페이스에 따라서 동작이 가능하게 하는 방식이다.
일반적인 경우에 Command패턴과 Strategy Pattern을 적용해서 많이 사용한다.

2011년 1월 25일 화요일

Java로 Twitter4j를 이용해서 트위터읽기

우선은 코드만 올려두고 나중에 인증과정에 대한 설명이나 실행 방법 설명 추가할 예정


import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;

import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.http.AccessToken;
import twitter4j.http.RequestToken;


public class OAuthEx {

 public static void main(String args[]) throws Exception{
   // The factory instance is re-useable and thread safe.
   Twitter twitter = new TwitterFactory().getInstance();
   twitter.setOAuthConsumer("소비키", "소비비밀키");
   RequestToken requestToken = twitter.getOAuthRequestToken();
   AccessToken accessToken = null;
   BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
   while (null == accessToken) {
     System.out.println("Open the following URL and grant access to your account:");
     System.out.println(requestToken.getAuthorizationURL());
     System.out.print("Enter the PIN(if aviailable) or just hit enter.[PIN]:");
     String pin = br.readLine();
     try{
        if(pin.length() > 0){
          accessToken = twitter.getOAuthAccessToken(requestToken, pin);
        }else{
          accessToken = twitter.getOAuthAccessToken();
        }
     } catch (TwitterException te) {
       if(401 == te.getStatusCode()){
         System.out.println("Unable to get the access token.");
       }else{
         te.printStackTrace();
       }
     }
   }
   //persist to the accessToken for future reference.
   storeAccessToken(twitter.verifyCredentials().getId() , accessToken);
   Status status = twitter.updateStatus("아... 이거 때문인가????");
   System.out.println("Successfully updated the status to [" + status.getText() + "].");
 

   System.exit(0);
 }
 private static void storeAccessToken(int useId, AccessToken accessToken){

 System.out.println("useId : " + useId);
 System.out.println("AccessToken : " + accessToken);

 FileOutputStream fos = null;
 ObjectOutputStream oos = null;
 try{
 fos = new FileOutputStream("key.data");
 oos = new ObjectOutputStream(fos);

 oos.writeInt(useId);
 oos.writeObject(accessToken);

 }catch(Exception e){
 e.printStackTrace();
 }finally{

 try {
oos.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

 try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
 }
 }

}

2011년 1월 24일 월요일

초간단 이미지 만들기

JDK1.4에서부터는 공식 API에서 이미지 입출력 기능이 제공되기 시작한다.
따라서 아주 간단한 몇 라인의 코드만으로 이미지를 생성하는 것이
가능한데..

약간만 활용하면 카페나 사이트에서 사용하는 해킹 방지용 문자를 만들때 유용하다.




package com.util;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
public class TempPasswordMaker {

 public static void makeImage(OutputStream out, String msg)throws Exception{
  BufferedImage image = null;
  image = new BufferedImage(300,150, BufferedImage.TYPE_INT_RGB);
  Graphics g = image.createGraphics();
  g.setColor(Color.WHITE);
 
  g.setFont(new Font("Courier",Font.BOLD,22));
  g.fillRect(0, 0, 300, 150);
  g.setColor(Color.black);
  g.drawString(msg, 10, 70);
 
  Iterator imageWriters = ImageIO.getImageWritersBySuffix("jpg");
  ImageWriter imgWriter = null;
 
  while(imageWriters.hasNext()){
   imgWriter = (ImageWriter)imageWriters.next();
   System.out.println("IMGWRITER:"+ imgWriter.toString());
  }
  ImageIO.write(image, "jpg", out);
 }

 public static void main(String[] args)throws Exception{
 
  FileOutputStream fos = new FileOutputStream("aaa.jpg");
  makeImage(fos,"AAAAAAAAAAA");
 
 }
}

2011년 1월 18일 화요일

[도서추천] Writing Effective Use cases


절판되어서 너무나 아쉬웠던 책이 다시 나왔다.
예전에 단순코더에서 개발자의 세계로 나를 이끌어 주었던 책!

중간에 잃어버려서 너무 맘아팠던 책!

프로그래밍이란 하나의 글쓰기이다.
그리고 그 글을 어떻게 써야하는지를 설명해 준 책이다.

단순히 프로그래밍 뿐 만이 아니라
논리적인 업무를 하는 사람이라면 한번쯤 읽어보라고 추천하고 싶은 책이다.

왜 수많은 디자인패턴은 인터페이스로 구현하게 되는가?

아마도 Java를 공부하는데 있어서 가장 험난한 고비는 역시 interface가 아닌가 싶다.
하긴 나도 인터페이스를 10년이 넘은 지금도 '이게 최선입니까? , 확실해요? '라는 질문을 던지고 있으니 초급자들에게는 가장 넘기 어려운 산일 것이다.

상속이라는 것은 초급자들이 좀 쉽게 적응을 할 수 있다는 것은 너무나 명확한 사실인듯하다.

하지만 인터페이스의 경우는 어떤가? 솔직히 전혀 아니올시다..

그럼 여기서 우리가 한번 생각해 봐야하는 것은 '왜 그 수많은 객체지향 디자인 패턴은 상속보다는 인터페이스를 사용하는가?'이다.

우선 인터페이스의 몇 가지 특징을 생각해 보자.

인터페이스는 컴파일러가 인식하는 하나의 코드에 대한 스펙을 의미한다.

즉 어떤 객체이건 간에 특정 메소드를 오버라이드하고 있는 객체라면 컴파일러는 지나칠 수 있다는 뜻이다.
사실 이 특징은 다형성이라는 것이 가지는 장점이라고 생각해도 되고, 상속 역시 다형성의 일부이기 때문에 굳이 인터페이스에 국한된 설명이라고 할 수는 없다.


인터페이스는 온갖 다른 클래스를 하나의 타입과 동일한 메소드의 오버라이드라는 놀라운 효과를 가져온다.
아무리 다른 로직들(메소드들)과 데이터를 가진 객체들이라고 할 지라도 동일한 인터페이스를 구현하므로 인해서 모든 객체들을 하나의 타입으로 아우룰수 있는 최고의 방법이다.
흔히들 Java에서 인터페이스를 'Java의 꽃'이라고 부르는 것도 이러한 이유이다.

켄트 백의 말처럼 인터페이스의 가장 무서운 점은 '인터페이스를 바라보고 코드를 작성할 때에는 실제 인터페이스 너머에는 어떤 객체가 존재하는지 신경쓰지 않아도 된다'는 점이다.

-------------------------------------------------------------------------------
인터페이스가 왜 유연한지 생각해보자면 가장 쉽게 점심메뉴를 생각해 보시라..

'오늘은 카레를 먹을꺼야' VS '오늘은 따끈한 국물요리를 먹을꺼야'

'카레'를 먹는 방식은 클래스와 객체 방식이다. 왜냐하면 이 말을 통해서 우리가 바로 어떤
실체를 떠올릴 수 있기 때문이다.

반면에 '따끈한 국물요리'는 인터페이스 방식이다. 이 말을 통해서는 실체를 떠올릴 수는 없다. 왜냐하면 너무나 많은 국물 요리 후보 객체가 생겨버리기 때문이다.

객체지향이 현실세계를 모델로 한다고 하자. 우리가 점심메뉴는 어떤 방식을 선택하는가?
클래스인가? 아님 인터페이스 인가?