2010년 12월 29일 수요일

Python file write,read

File I/O for "newbie"

Not a bad site at all
#Write a file
#this opens a file named test.txt
#the string is written to the file then the file is closed
out_file = open("test.txt","w")
out_file.write("Write what you want inside here!\n")
out_file.close()
#Read a file
#open the same file, but read it this time
#read the file as string data
in_file = open("test.txt","r")
text = in_file.read()
#or text = in_file.readline()
in_file.close()
print text

Builder pattern example

public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;

public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;

// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;

public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}

public Builder calories(int val)
{ calories = val; return this; }
public Builder fat(int val)
{ fat = val; return this; }
public Builder carbohydrate(int val)
{ carbohydrate = val; return this; }
public Builder sodium(int val)
{ sodium = val; return this; }

public NutritionFacts build() {
return new NutritionFacts(this);
}
}

private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}

public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
calories(100).sodium(35).carbohydrate(27).build();
}
}

Builder 패턴은..

1. Builder 패턴은..

뭔가가 만들어 지는 과정은 꽤나 복잡할 수가 있습니다. 게다가 그 복잡한 과정이 순서대로 실행되어야 할 때도 있습니다. 객체의 생성에 있어서 이런 복잡한 과정들을 분리해 내는 것이 Builder 패턴입니다.

2. 예제

---------------- 복잡한 과정을 거쳐서 만들어 지는 객체가 될 Hero 클래스 ----------------

package ch14_builder;

public class Hero {
private String armSource;
private String legSource;
private String name;

public Hero(String name) {
super();
this.name = name;
}
public void setArmSource(String armSource) {
this.armSource = armSource;
}
public void setLegSource(String legSource) {
this.legSource = legSource;
}
public void showResult(){
System.out.println(armSource +"로 만든 팔과 " + legSource +"로 만든 다리를 가진 " + name);
}
}

---------------- 복잡한 Hero 객체를 만들어내기 위한 객체 생성과정을 관리하는 Builder 인터페이스 ----------------

package ch14_builder;

public interface Builder {
void makeArm();
void makeLeg();
Hero getResult();
}

---------------- 복잡한 Hero 객체를 실제로 만들어내는 Builder의 구현체인 배트맨 찍어내는 클래스 ------------------

package ch14_builder;

public class BatmanBuilder implements Builder {
private Hero batman;
BatmanBuilder(){
batman = new Hero("배트맨");
}
public void makeArm() {
batman.setArmSource("돈지랄");
}
public void makeLeg() {
batman.setLegSource("돈지랄");
}
public Hero getResult() {
return batman;
}
}

---------------- Builder를 관리해 주는 Director ----------------

package ch14_builder;

public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void build(){
builder.makeArm();
builder.makeLeg();
}
public Hero getHero(){
return builder.getResult();
}
}

---------------- Director를 이용해 Hero를 찍어내는 Test클래스 -------------

package ch14_builder;

public class Test {
public static void main(String[] args) {
Builder builder = new BatmanBuilder();
Director director = new Director(builder);
director.build();
Hero hero = director.getHero();
hero.showResult();
}
}

---------------- 테스트 결과 -------------
돈지랄로 만든 팔과 돈지랄로 만든 다리를 가진 배트맨

Hero 라는 클래스가 있습니다. 이 클래스는 그냥 생성자만 호출해서는 아무 쓸모없는 클래스입니다. 이런 저런 정보들이 많이 쎄팅이 되어야 비로소 쓸만한 객체가 됩니다.(예제에서는 setArmSource()과 setLegSource()와 같은 게 그런 복잡한 세팅 과정에 관여하는 메쏘듭니다.) 따라서 이 클래스의 객체를 생성하는 과정은 매우 번거롭습니다.
이런 번거로운 과정을 Director에서 간단하게 build()라는 메쏘드로 해결을 하려고 합니다. build()라는 메쏘드는 참 간단한 것 같은데, 번거로운 과정을 어떻게 다 커버하느냐는 결국 Builder에 위임해서 해결합니다.
Builder는 비교적 세부적인 사항들을 다룹니다. 이에 비해 Director는 좀 더 포괄적인 과정은 다룹니다. 위의 예제의 경우는 Builder는 팔은 어떻게 만들어 지고 다리는 어떻게 만들어지는 지 등과 같은 것을 다루며(세부적인 사항인 makeArm(), makeLeg()와 같은 메쏘드), Director는 팔을 만들고 다리를 만들면 대략 Hero 하나 완성시킬 수 있다는 전체적인 로직(포괄적인 과정인 build() 메쏘드)을 다룹니다. 즉, Director는 다른 Hero를 만드는데도 활용할 수 있지만, Builder는 각각의 Hero에 국한됩니다.

위의 예제는 예제인 만큼 간단하게 만들었습니다만, Hero를 만들기 위해서 수십수백 가지의 정보가 세팅되어야 한다고 칩시다. 이럴 때, Hero의 생성자에 그런 정보들을 다 세팅해줄 수는 없습니다.

3. UML을 벗어나서...

위 에서는 등장인물이 Builder(interface)와 그 구현체들, 그를 관리하는 Director 그리고 만들어지는 생산품(Hero) 등이 있었습니다. 그러나, 이는 그냥 전형적이 UML 모냥새를 나타내는 것 뿐이고, Builder 패턴에 있어서는 저런 UML을 벗어나는 경우들이 허다합니다.
Builder에서의 포인트는 "뭔가 복잡한 과정을 거쳐 만들어지는 객체가 있는데, 이때 이 복잡한 과정을 Builder에게 담당시키겠다"는 것입니다. 따라서 Builder와 Product 두 개만으로도 구성될 수 있습니다. 즉, Builder 자체가 Abstract Class나 인터페이스가 아니라 그냥 클래스 일수도 있습니다.
StringBuilder와 같은 것이 대표적인 예입니다. StringBuilder는 이름 그대로 String을 만들어냅니다. 코드를 봅시다.

String ab = new StringBuilder("a").append("b").toString();

여기서 StringBuilder는 결국 "ab"라는 String을 만들기 위한 것입니다. StringBuilder 자체가 의미를 가지는 것이 아니라, 만들어 내는 String이 의미를 가지는 것입니다.

4. Builder를 쓰면 좋은 경우

같은 클래스의 인자를 여러 개 받은 Constructor를 생각해봅시다.

public class Person{
private final String name;
private final String city;
public Person(Stirng name, String city){ //인자가 둘 다 String
this.name = name;
this.city = city;
}
//getter는 생략.
}

이 코드는 다음과 같이 호출되어야 합니다.
Person p = new Person("홍길동", "서울");

그런데, 인자가 둘 다 String이라 다음과 같은 실수가 있을 수도 있죠.
Person p = new Person("서울", "홍길동"); // 앞 뒤가 바뀜!

이러면 "서울"에 사는 "홍길동"씨가 아니라, "홍길동"에 사는 "서울"씨가 만들어집니다.

Person p = new PersonBuilder().setName("홍길동").setCity("서울").build();

와 같이 호출된다면, 앞 뒤가 바뀔 가능성이 별로 없겠지요.

(PersonBuilder는 생략합니다.)

이번에는 다음과 같은 복잡한 클래스를 생각해 봅시다.

public class Complex(){
private Object member1;
등등등 수많은 member 변수..
public void set1(Object arg) { member1 = arg;}
등등등 수많은 setter..
public Object get1() { return member1;}
등등등 수많은 getter..
}

------ Complex를 만들어 내는 클라이언트 ----
Complex complex = new Complex();
complex.set1(...);
여러 개의 setter 호출....

------ Complex를 가져다 쓰는 클라이언트 ----
complex.get1();
여러 개의 getter 호출

이 클래스의 사용 코드를 보면, 복잡하게 만들어내는 부분과 가져다가 사용하는 부분이 명확하게 분리가 되어있습니다. 따라서 다음과 같은 요구가 있을 수 있습니다.

1. 한번 세팅된 값은 변하면 안 된다.
2. getter는 모든 member 변수가 세팅이 된 후에만 사용할 수 있다.

모든 setter는 수정하려는 변수가 세팅이 되어있는지 확인해야 하고, 모든 getter에서는 모든 member 변수가 세팅이 되었는지 확인해야 합니다. 이런 경우 코드가 다음과 같이 좀 지저분하게 수정되어야 합니다.

public class Complex(){
private Object member1;
등등등 수많은 member 변수..
private boolean completed(){
//member 들이 세팅이 전부 완료되었는 지를 체크해서 리턴.
}


public void set1(Object arg) { if(member1 != null) throw new IllegalStateException("세팅 중복") member1 = arg;}
등등등 수많은 setter..
public Object get1() { if(!completed()) throw new IllegalStateException("세팅 미완료") return member1;}
등등등 수많은 getter..
}

모 든 getter 들에서 세팅이 완료되었는지 체크하는 로직이 들어가야 합니다. completed() 안의 부분을 효율적으로 바꿀 수는 있지만, getter에서 IllegalStateException이 발생하는 것은 근본적으로 막을 수는 없습니다.

여 기서의 문제는 Complex 클래스를 한 번에 만들어내지 못한다는 것이었습니다. 이럴 경우 만들어내는 복잡한 과정을 ComplexBuilder를 만들어서 해결하면 됩니다. 또 ComplexBuilder는 오로지 Complex 클래스를 만들어내기 위한 클래스입니다. 따라서 ComplexBuilder를 분리하면 됩니다.

public class ComplexBuilder{
private Object member1;
등등등 수많은 member 변수..
public void set1(Object arg) { member1 = arg;}
등등등 수많은 setter..
//여기는 getter가 있을 지 없을 지 생각 좀 해보고 필요에 따라 넣던지 빼던지...
public Complex build(){
//Complex 객체를 만드는 과정을 전부 넣어둠.
}
}

public class Complex(){
Complex(){} //public constructor를 제공하지 않음.

private Object member1;
등등등 수많은 member 변수..
void set1(Object arg) { member1 = arg;} // public이 아님!!
등등등 수많은 setter..
public Object get1() { return member1;}
등등등 수많은 getter..
}

위와 같이 2개의 클래스를 같은 패키지에 넣어두고 쓰면 됩니다.

이를 사용하는 코드는 아래와 같이 됩니다.

------ Complex를 만들어 내는 클라이언트 ----
ComplexBuilder cb = new ComplexBuilder();
cb.set1(...);
여러 개의 setter 호출....
Complex complex = cb.build();

------ Complex를 가져다 쓰는 클라이언트 ----
complex.get1();
여러 개의 getter 호출

일단 Complex는 public constructor를 제공하지 않도록 했습니다. 잘못된 객체 생성을 막고, 오로지 ComplexBuilder를 통해서만 만들어지게 합니다. 또 Complex의 setter 들도 public이 아닙니다. 즉, 외부에서 변수를 세팅하지 못하도록 막았습니다. 따라서 멤버 변수가 변경될 수 있는 가능성을 근본적으로 막아버렸습니다. 그리고 getter에서 member 변수가 세팅이 되었는지를 일일이 확인할 필요도 없어졌습니다.

간략히 정리하면, 복잡하게 만들어지는 Immutable 클래스는 Builder를 통해 만들면 편하다는 얘기죠.



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


5. Factory 패턴과의 차이점


Factory와 Builder는 모두 객체 생성에 관련된 패턴이고 둘이 좀 비슷해보이기도 합니다. 그러나 용도가 좀 다릅니다.

Factory는 일반적으로 다음의 두 가지 경우에 해당하는 경우에 사용합니다.

1. 리턴 타입이 일정하지 않은 경우. 예를들어, create("소") 라고 하면 Cow 클래스의 인스턴스를 리턴하고, create("개")라고 하면 Dog 클래스의 인스턴스를 리턴하는 것처럼 인자에 따라 리턴 타입이 바뀌는 경우.
2. 대략 비슷하지만 멤버가 살짝 다른 경우. Boolean.valueOf(String arg) 와 같은 경우 리턴 타입은 모두 Boolean 이지만, 속의 내용이 조금 다름. 이 경우는 대부분 Singleton 패턴으로 처리됨.

그러나 Builder는 객체 생성과정의 복잡성을 떠넘기는 게 포인트입니다.

Free Web editor

http://www.kompozer.net/

Eclipse plugin editor

JavaScript tuturial

http://www.w3schools.com/js/default.asp

자바 패턴및 정규식 정리사이트

자바 패턴및 정규식 정리사이트

Immutable이란..

Immutable이란..

Immutable 이란 생성후 변경 불가한 객체입니다. 그래서 immutable에는 set 메쏘드가 없습니다. 멤버 변수를 변경할 수 없습니다. return type이 void인 메쏘드도 없습니다. 주로 void 메쏘드는 뭔가를 하고(하지 않을 수도 있고.. ) 멤버변수를 변경하는 역할을 하는 것이기 때문에 쓸 일이 거의 없습니다. (물론, 콘솔에 뭔가를 찍는 것과 같은 예외적인 void는 있을 수 있습니다.)
Immutable을 쓰면, 멀티 쓰레드 환경에서 좀 더 신뢰할 수 있는 코드를 만들어 내기가 쉽습니다. 멀티 쓰레드 프로그램을 짜보셨다면 아시겠지만, 멀테 쓰레드 환경에서는 에러보다 비정상적 작동의 경우가 많습니다. 에러도 아니기 때문에 찾아내기도 어렵습니다. 게다가 항상 생기는 것도 아니고 백번에 한번 천번에 한번 식으로 문제가 생겨 정말 머리 아픈 경우가 한 두번이 아닙니다.
Immutable을 쓰게 되면, 이런 요소들을 많이 줄일 수 있습니다.

대표적인 Immutable 클래스

String, Boolean, Integer, Float, Long 등등이 있습니다. 여기서 주의할 점은 변경불가라는 것은 heap 영역에서의 변경불가라는 뜻입니다. String a="a"; a="b"; 와 같이 재할당은 가능합니다. 이는 a가 reference하고 있는 heap 영역의 객체가 바뀌는 것이지 heap영역에 있는 값이 바뀌는 것이 아닙니다.

String vs StringBuffer

String 과 StringBuffer에는 비슷한 메쏘드들이 많이 있어서 비슷해 보이지만, 결정적인 차이가 있습니다. String은 Immutable 입니다. StringBuffer는 아닙니다. StringBuffer가 String에 비해서 훨씬 빠르다는 얘기를 들어보셨나요? 그건 객체를 새로 생성할 필요가 없기 때문입니다.

String에는 없고 StringBuffer에만 있는 대표적인 메쏘드는 append, delete 등일 겁니다. 멤버 변수를 변화시켜 값을 바꿀 수 있는 거죠. 그런데 잘 보며 이들의 리턴은 StringBuffer 타입입니다. 어차피 얘네도 객체를 새로 만들어낸다면, String과 별 차이가 없어보입니다. 그러나 객체를 새로 만들어 내는 것이 아닙니다.
아래 코드를 실행시켜보세요.
StringBuffer b = new StringBuffer();
StringBuffer a = b.append("test");
System.out.println(a == b);
true가 나옵니다. 객체를 새로 만드는 것이 아니라 return this 로 되어있습니다. 굳이 리턴을 하는 이유는 아래와 같은 코딩을 가능하게 해주려는 것 같습니다.

StringBuffer test = new StringBuffer();
test.append("a").append("b").append("c").append("d");

와 같은 식으로 여러줄 코딩을 한 줄로 할 수 있게 해주려는 것 같습니다.. 아님 말구요.-_-;

Immutable의 유용성과 위험성

멀티쓰레드 환경에서 하나의 객체에 접근을 하는데 각각의 쓰레드끼리는 영향을 받으면 안 되는 경우가 있습니다. 그럴 때 한 번 만들어진 객체의 값이 변하지 않는다는 게 보장이 되면 편하겠죠.

String a = "";
while(어떤 조건문){
a += "머시기";
if(딴 조건문){
break;
}
}

위 와 같은 코드는 쓰면 안 됩니다. a+= "머시기" 구문이 문젭니다. 객체를 계속 생성해 냅니다. Immutable은 값이 계속 변경될 수 있는 곳에 쓰면 메모리 왕창 잡아먹습니다. 값이 완전히 정리된 후에 한 큐에 immutable로 만들어 내셔야 합니다. (물론, 가비지 컬레션이 돌면서 정리를 하기 때문에 치명적으로 위험한 수준의 행동은 아닙니다.)

java.util.Collections 에 unmodifiable머시기 하는 메쏘드들이 있습니다. 얘네들을 이용하면, Set, List, Map 등을 immutable로 사용할 수 있습니다. 다만, add, put과 같은 메쏘드를 호출할 경우에는 UnsupportedOperationException 가 발생합니다. 예외 상황을 고려해야 합니다.

Immutable은 보통 final 클래스로 정의합니다.

처 음에 자바를 할 때 String이란 객체에 ltrim이란 메쏘드를 추가하고 싶었습니다. (왼쪽만 trim하는 메쏘듭니다.) 상속을 받아 새로운 클래스를 만들어 해결하려고 했습니다. 헛, 그런데 final로 정의가 되어있어서 상속을 받을 수가 없더군요.
final로 정의가 되지 않으면, 상속을 받은 클래스가 Immutable을 깨버릴 수가 있기 때문입니다.

잘못된 Immutable의 구현

package immutable;

import java.text.SimpleDateFormat;
import java.util.Date;

public final class WrongImmutable {
private final Date date;
private final SimpleDateFormat dateFormat;
public WrongImmutable(Date date){
this.date = date;
dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
public String getMessage(){
return dateFormat.format(date);
}
}

위 의 소스를 보세요. date라는 변수가 final로 정의 되어있으며, setter가 없어 오직 생성자에서만 값을 지정할 수 있는 것 같아보입니다. 그러나 아래와 같은 테스트 클래스를 실행시켜보시면, 위의 코드가 잘못되었음을 알 수 있습니다.

package immutable;

import java.util.Date;

public class WrongImmutableTest {
public static void main(String[] args) {
Date testDate = new Date();
WrongImmutable wrongImmutable = new WrongImmutable(testDate);
testDate.setTime(testDate.getTime() + 10000000);
System.out.println(wrongImmutable.getMessage());
}
}

WrongImmutable의 생성자에 인자로 넣은 Date를 외부에서 값을 변경시키면 WrongImmutable의 멤버 변수의 값이 변경이 되고 맙니다. Immutable에서는 멤버 변수가 외부로 공개되어 변경이 가능하면 안 됩니다.
그럼 처음에 원했던 대로 정상적인 Immutable이 되도록 하려면 인자로 받은 Date 객체를 그대로 사용하는 것이 아니라, 어떤 식으로든 복사를 해서 써야 합니다. 생성자에서 멤버 변수의 값을 할당하는 부분을

this.date = new Date(date.getTime());
와 같이 바꿔야 합니다.

자바에 진짜 Immutable이란 건 없다!

java의 reflection을 이용하면 변경 가능합니다. 다음 코드를 실행시켜 보세요.

import java.lang.reflect.Field;

public class EditUsingReflection {
public static void main(String[] args) throws IllegalArgumentException, SecurityException, IllegalAccessException, NoSuchFieldException {
String s = "string!";
edit(s);
System.out.println(s);
}
public static void edit(String s) throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException {
Field stringValue = String.class.getDeclaredField("value");
stringValue.setAccessible(true);
stringValue.set(s, s.toUpperCase().toCharArray());
}
}

String 객체는 내부적으로 value라는 이름의 char[]로 그 값을 관리합니다. 물론 private으로 선언되어있지요.
reflection 을 이용하면 멤버변수에 걸려있는 private을 무시하고 접근해 버릴 수가 있습니다. 결국 reflection을 이용하면 모든 멤버변수에 대한 수정이 가능합니다. Immutable이란 건 reflection을 제외시켜 놓고 생각할 때만 가능합니다.

Sington Pattern

1. Singleton 패턴은..

각 종 설정 등이 저장된 클래스가 하나 있다고 칩시다. 프로그램 내에서 여기저기서 마구 접근해서 설정을 바꾸기도 하고 값을 가져오기도 합니다. 이런 클래스는 인스턴스를 하나만 가져야 합니다. 하나 만들어서 쓰는 곳마다 인자로 전달해주면 되긴 합니다만, 접근하는 곳이 많다면, 계속 인자로 전달하는 것은 그다지 바람직하지 않습니다. 전역변수처럼 아무곳에서나 이 인스턴스에 접근을 하면 편하겠죠. Singleton 패턴을 이용하면, 하나의 객체를 만들어서 아무데서나 접근할 수 있습니다.

2. 예제

--------------------- Singleton으로 구현된 클래스 ----------------
package ch05_Singleton;

public class SingletonCounter {
private static SingletonCounter singleton = new SingletonCounter();
private int cnt = 0;
private SingletonCounter(){
}

public static SingletonCounter getInstance(){
return singleton;
}

public int getNextInt(){
return ++cnt;
}
}
---------------------- 테스트 클래스 ---------------------
package ch05_Singleton;

public class Test {
public static void main(String[] args) {
Test t = new Test();
t.Amethod();
t.Bmethod();
}
public void Amethod(){
SingletonCounter sc = SingletonCounter.getInstance();
System.out.println("Amethod에서 카운터 호출 " + sc.getNextInt() );
}
public void Bmethod(){
SingletonCounter sc = SingletonCounter.getInstance();
System.out.println("Bmethod에서 카운터 호출 " + sc.getNextInt() );
}
}

---------------------- 실행 결과 -----------------------
Amethod에서 카운터 호출 1
Bmethod에서 카운터 호출 2


singleton에서 중요한 것은 다음 세 가지입니다.
첫째, private 멤버 변수로 자기 자신의 클래스의 인스턴스를 가집니다. 황토색 부분입니다.
둘째, private 생성자를 지정하여, 외부에서 절대로 인스턴스를 생성하지 못하게 합니다. 보라색 부분입니다.
셋째,getInstance() 메쏘드를 통해 객체를 static하게 가져올 수 있습니다. 파란색 부분입니다.

이는 유일무이한 인스턴스를 만들기 위해 생긴 규약들입니다. 무슨 수를 써도 Singleton 클래스를 수정하지 않는 한 새로운 인스턴스를 만들 수 없습니다.

3. Singleton을 구현하는 몇 가지 방법

------------- 첫번째 --------------
package ch05_Singleton;

public class Singleton1 {
private static Singleton1 single = new Singleton1();
public static Singleton1 getInstance(){
return single;
}
private Singleton1(){
}
}

클래스 로드시 new가 실행이 됩니다. 항상 1개의 인스턴스를 가지게 되겠죠. 코드가 가장 짧고 쉽습니다. 성능도 다른 방법에 비해 좋습니다.

-------------- 두번째 --------------
package ch05_Singleton;

public class Singleton2 {
private static Singleton2 single;
public static synchronized Singleton2 getInstance(){
if (single == null) {
single = new Singleton2();
}
return single;
}
private Singleton2(){
}
}

클 래스 로드시에는 인스턴스가 생성되지 않습니다. getInstance()가 처음 호출될 때 생성이 되지요. 그러나 synchornized가 걸려 있어서 성능이 안 좋습니다. 인스턴스를 사용할 필요가 없을 때는 인스턴스가 생성되지 않는다는 점이 첫번째 방벙에 비해 장점입니다.

--------------- 세번째 ---------------
package ch05_Singleton;

public class Singleton3 {
private volatile static Singleton3 single;
public static Singleton3 getInstance(){
if (single == null) {
synchronized(Singleton3.class) {
if (single == null) {
single = new Singleton3();
}
}
}
return single;
}
private Singleton3(){
}
}

첫번째의 장점인 성능이 좋다(synchronized 가 안 걸려서)와 두번째의 장점인 안 쓸 때는 인스턴스를 아예 만들지 않는다의 장점만 뽑아온 방법입니다. 코드는 제일 깁니다^^.
여기서 중요한 점은 if(single == null) 을 두 번이나 체크합니다. A, B 2개의 thread가 접근을 한다고 가정합니다.
A 와 B가 거의 동시에 들어와서 바깥쪽 single== null 인 부분을 통과했다고 칩시다. 그리고 A가 조금 먼저 synchronized 블럭에 진입했습니다. B는 그 앞에서 대기 중이지요. A가 다시 single== null을 체크합니다. 여전히 null이지요. 그러면 인스턴스를 만들고 synchronized 블럭을 탈출합니다. 그러면 B가 synchronized 안으로 진입합니다. single은 더 이상 null이 아닙니다. A가 만들었으니까요. B는 그냥 synchronized 블럭을 빠져나옵니다.
바깥쪽 if(single == null) 가 없다면, 성능 저하가 발생합니다. 매번 synchronized 블럭 안으로 들어가니까요. 두번째 방법과 같다고 보시면 됩니다. 안쪽의 if(single == null) 가 없다면, singleton이 보장되지 않습니다.
volatile 키워드도 꼭 써줘야 합니다. volatile 키워드는 변수의 원자성을 보장합니다. single = new Singleton3(); 이란 구문의 실행은 원자성이 아닙니다.(원자성이란 JVM이 실행하는 최소단위의 일을 말합니다. 즉 객체 생성은 JVM이 실행하는 최소단위가 몇 번 실행되어야 완료되는 작업이란 뜻입니다.) JVM에 따라서 single이라는 변수의 공간만을 먼저 생성하고 초기화가 나중에 실행되는 경우도 있습니다. 변수의 공간만 차지해도 null은 아니기 때문에 singleton이 보장된기 어렵습니다. JVM 버전이 1.4(어쩌면 1.5 잘 기억이..--;; ) 이전에서는 volatile 키워드가 정상적으로 작동하지 않을 수도 있다고 합니다.

--------------- 네번째 ---------------
package ch05_Singleton;

public class Singleton4 {
private Singleton4(){
}
private static class SingletonHolder{
static final Singleton4 single = new Singleton4();
}
public static Singleton4 getInstatnce(){
return SingletonHolder.single;
}
}

네 번째 방법은 내부 클래스를 사용하는 방법입니다. 기존의 3가지 방법에서는 Singleton 클래스가 자기 자신의 타입을 가지는 멤버 변수를 가지고 있는데, 네번째의 경우는 내부 클래스가 가지고 있습니다. 내부 클래스가 호출되는 시점에 최초 생성이 되기 때문에, 속도도 빠르고 필요치 않다면 생성하지도 않습니다.

4. Singleton의 특징

Singleton 은 당연히 인스턴스가 1개만 생깁니다. 그러자고 만든 거니까요. 또 하나의 규약은 private 생성자 때문에 상속이 안 된다는 점입니다. (상속받은 하위체는 상위체의 생성자를 호출합니다.) 예를 들어 Singleton에서 설정관련된 xml 파일을 수정한다고 칩시다. 상속을 받아 다른 객체를 만들어서 파일을 수정하는 시도를 하면 안되지요. 상속을 받게 되면 "인스턴스 1개"라는 원칙을 깨게 됩니다.
private 생성자는 외부에서의 직접호출을 통한 생성을 막는 것과 상속을 막는 두 가지 기능을 수행합니다. 둘 다 "인스턴스 1개"라는 원칙을 지키는 것이죠.

Factory 패턴과 사용법이 매우 유사합니다. Singleton은 Factory의 특이 케이스로 볼 수도 있습니다. Factory는 매번 객체를 만들어서 리턴하는 방법이고 Singleton은 한 개만 만들어서 요청이 들어올 때마다 만들어진 객체를 리턴한다는 게 차이점입니다. 또 일반적으로 Factory는 create...과 같은 메쏘드 이름을 사용하고 Singleton은 getInstance라는 메쏘드 이름을 사용합니다.

위에서 말한 세가지 방법 중 첫번째 방법의 경우는 public으로 멤버 변수를 선언하고 외부에서 직접 변수에 접근해서 사용하게 해도 됩니다. (반드시 private이어야할 필요는 없다는 거죠. ) 두번째와 세번째는 초기화가 보장이 안 되어 있지만, 첫번째의 경우는 보장되어있기 때문입니다. 주의할 점은 외부에서 악의적으로 public 멤버 변수는 바꿔치기를 할 수도 있기 때문에 이런 식으로 접근할 때는 final 을 붙여주는 게 좋습니다.(어차피 private 생성자를 가지고 있으니, 외부에서 새로운 객체를 만들어 낼 수는 없지만 null을 대입할 수는 있기 때문에 final이 필요합니다.) 그럼 public static final이 되는군요! 상수란 말이죠. 하지만 일반적인 상수와는 다릅니다. 일반적인 상수는 Immutable 로 구현이 되어있기 때문입니다. 상수로 많이 쓰는 String, Integer, Boolean 등은 전부 Immutalbe입니다.
물론 이런 접근이 권장사항은 아닙니다. 그냥 가능하긴 하다는 얘깁니다.

2010년 12월 28일 화요일

vmware tools install

우분투를 설치하고나서 VMware Tools를 설치해보자.
환경 : VMware 6.0.0.45731, ubuntu 8.04

설치방법은 Ctrl + Alt 키를 눌러 커서 제어권을 윈도우 VMware 로 가져온다.
다음 메뉴의 VM - Install VMware Tools 를 누룬다.
그럼 아래와 같이 바탕화면에 패키지가 마운트 된다.

내용물중에 VMware***.tar.gz 를 임의 폴더에 압축을 해제한다.

!! 참고 설치전 root 권한을 아직 안햇다면 미리 작업을 하고자자
터미널창을 연다.
$ sudo gdmsetup
또는 패널에서 [시스템] - [관리] - [로그인 창] 메뉴를 클릭해 [로그인 창 기본 설정]을 실행한다.
[보안]탭 옵션중 [로컬 시스템 관리자 로그인 허용(A)]을 체크해준다.

Alt + F2 키를 눌러 [프로그램 실행]창에서 gksudo nautilus 를 입력하고 실행한다.
여기서 좀전 임의장소에 압축을 해제한 vmware-tools-distrib 폴더를 방금 열린 root 폴더로 복사를 해온다.

복사된 vmware-tools-distrib 폴더안에서 vmware-install.pl를 실행후 창이 뜨면 [터미널에서 실행]을 누른다.

다음 터미널 창이 뜨면서 설치가 시작된다. 무조건 Enter 만 치면된다.

설치 완료후 재부팅을 하면 된다.



미아를 찾습니다

vmware shared folder

shared folder

VMware 와 우분투 환경에서 VMware tools 설치하기

개발환경 : VMWare 6.5.3 , Ubuntu 9.10

우분투 처음 설치후 화면이 작아서 어떻게 하면 키워볼까 고민하던중

vmware tool 을 설치하면 된다고 해서 그 과정을 밟아 보았다.

1. vmware tools 를 설치하기 위한 개발 환경 설정

$ sudo apt-get install build-essential linux-headers-`uname -r` psmisc


2. ctrl+alt 로 화면을 빠져 나간후 VM > Reinstall VMware Tools 를 클릭한다

바탕화면에 VMware Tools DVD 아이콘이 뜨고 DVD 내부 파일들을 보여주는

폴더가 보여진다. 그 폴더내부에 VMwareTools-7.8.6-***.tar.gz 가 보이는데 이것의

압축을 풀고


3. Desktop 에 압축을 풀었다면 콘솔에서 ~/Desktop/vmware-tools-distrib

폴더로 들어가 다음 sudo ./vmware-install.pl 을 실행한다.

설치 과정에서 Directory 선택 물음이 나오는데 설정그대로 enter 쳐서 넘어간다.


4. 설정이 끝났으면 재가동한다. 그리고 옵션설정창을 열어서 재설정해본다.

> vmware-toolbox 또는

> sudo vmware-toolbox


5 .설치가 끝났으면 DVD 를 언마운트 시킨다.

바탕화면에 DVD아이콘을 선택하고 오른쪽 마우스를 클릭해서 unmount 명령을 시행한다.

2010년 12월 27일 월요일

javacc



출처 : http://eclipse-javacc.sourceforge.net/

1. 메뉴 [Help] -> [Install New Software] 선택



2. [Install]창에서 [Add] 버튼 선택



3. 아래와 같이 입력하고 [OK] 버튼 선택

Name : JavaCC Plug-In
Location : http://eclipse-javacc.sourceforge.net/



4. JavaCC Eclipse Plug-in 선택하고 [Next] 버튼 선택



5. [Next] 버튼 선택



6. 라이센스 수용하고, [Finish] 버튼 선택



7. [OK] 버튼 선택



8. Plug-in 설치 완료 후, [Restar Now] 버튼을 선택하여 Eclipse을 다시 시작한다.



- jj 파일을 열어본 화면



- jj 파일에서 오른쪽 마우스를 선택하여 Compile 하기



- jj Compile 결과



- jj 파일 Compile 하여 생성된 java 파일들



python

python tutorial

python

[ 대화식 모드에서 혹은 다른 모듈에서 모듈 파일 실행하기 ]

파이썬 인터프리터 안에서 모듈 파일(파일로 만들어진 프로그램)을 수행하기 위한 방법은 다음 두가지가 있다.

우선 다음과 같은 modfile.py 모듈 파일이 만들어져 있다고 하자. (파이썬 모듈 파일 이름은 .py로 끝나야한다)


------------------------------------------------------------------------
#!/usr/bin/env python
#file: modfile.py

s = 'module file sample'

def add(a,b):
return a+b

print add(3,4)
------------------------------------------------------------------------------------

===== execfile 이용하기 =====

사용되는 빈도수는 작지만, 파이썬 인터프리터 안에서 파일을 수행한다면 'execfile'을 이용할 수 있다.

------------------------------------------------------------------------------------
>>> execfile('modfile.py')
7
>>> s
'module file sample'
>>> add(5,6)
11
>>>
------------------------------------------------------------------------------------

※ 만일 'execfile' 을 수행했을 때 다음과 같은 에러 메시지를 보게 된다면 저당된 모듈 파일의 위치를

차지 못했기 때문이다.

Traceback (innermost last):
FILE line 1, in?
execfile('modfile.py')
IOError : [Errno 2] No such file or directory

위와 같은 에러 발생시 세가지 해결 방법이 있다고 한다.


*************************************************************

1. 모듈 파일을 파이썬 인터프리터가 찾을 수 있는 디렉토리로 이동시키거나

2. 파이썬 인터프리터에게 모듈 파일이 저장된 디렉토리를 알려주는 것이다.

3. PYTHONPATH 환경변수를 변경한다. (전 장에서 했음)

*************************************************************

파이썬 인터프리터가 찾을 수 있는 디렉토리 목록을 알아보기 위해선 아래와 같이 한고 한다.

>>> import sys
>>> sys.path
['', '/usr/lib/python2.2', '/usr/lib/python2.2/plat-linux2', '/usr/lib/python2.2/lib-dynload',

'/usr/lib/python2.2/site-packages', '/usr/lib/python2.2/site-packages/gtk-2.0']
>>>

만약 첫번째 방법으로 해결 하려면 'modfile.py' 를 위에서 보인 목록 중 한 디렉토리로 이동하는 것이다.

(사실 이것은 임시적인 파일을 실행시키기에는 별로 좋은 방법이 아니다.) 이동하는 디렉토리가 시스템에서만

사용하는 장소가 되지 않도록 조심하라.

두 번째 방법은 다음과 같이 한다.

>>> import sys
>>> sys.path.append('디렉토리 경로명')

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


===== import로 수행하기 =====

가장 많이 사용되는 방법이다. 'import'를 사용하며 그 모듈에 있는 모든 전역 이름들을 모듈 이름을

통하여 사용할 수 있다.

------------------------------------------------------------------------------------
>>> import modfile
7
>>> modfile.s
'module file sample'
>>> modfile.add(6,7)
13
>>>
------------------------------------------------------------------------------------

위의 두 방법은 대화식 인터프리터에서만 수행할 수 있는 것은 아니다. 두 가지 모두 파이썬 문으로

표현된 것이므로 다른 모듈 파일에서도 사용이 가능하다.


2010년 12월 14일 화요일

UDP server test

[Java Tips] DatagramSocket을 이용한 간단한 UDP 서버/클라이언트 구현

Posted at 2009/10/22 12:08 // in Java Tips // by FrogInPot


자바에서는 UDP 통신을 위해서 DatagramSocket과 DatagramPacket을 제공합니다.
이번 팁에서는 DatagramSocket과 DatagramPacket을 이용하여 간단한 UDP 서버/클라이턴트를 구현해 보겠습니다.

UDP 통신을 위해서는 UDP 패킷을 받을 서버 Socket이 생성되어야 합니다.
Socket 생성 시는 다음과 같은 순서로 수행합니다.

1. DatagramSocket 생성 : 생성 시, Listen할 Port 지정
2. DatagramPacket 생성 : 데이터를 수신할 그릇이 되는 DatagramPacket 생성
3. DatagramSocket.receive() 호출 : 생성된 Socket의 receive method를 생성된 packet object를 파라미터로 하여 호출. receive method는 호출 후, packet이 수신될 때까지 대기를 하게 됨

간단하게 구현한 UDP 서버는 다음과 같습니다.


01.import java.io.IOException;
02.import java.net.DatagramPacket;
03.import java.net.DatagramSocket;
04.import java.net.SocketException;
05.
06.public class DatagramServer extends Thread {
07.
08.private DatagramSocket socket;
09.
10.public DatagramServer() throws SocketException {
11.super();
12.
13.// DatagramPacket을 받기 위한 Socket 생성
14.// 9999 : Listen할 Port
15.socket = new DatagramSocket(9999);
16.}
17.
18.public void run() {
19.while (true)
20.{
21.try
22.{
23.// 데이터를 받을 버퍼
24.byte[] inbuf = new byte[256];
25.
26.// 데이터를 받을 Packet 생성
27.DatagramPacket packet = new DatagramPacket(inbuf, inbuf.length);
28.
29.// 데이터 수신
30.// 데이터가 수신될 때까지 대기됨
31.socket.receive(packet);
32.
33.// 수신된 데이터 출력
34.System.out.println("received length : " + packet.getLength() + ", received data : "
35.+ new String(packet.getData(), 0, packet.getLength()));
36.} catch (IOException e)
37.{
38.e.printStackTrace();
39.}
40.}
41.}
42.
43.public static void main(String args[]) throws SocketException{
44.DatagramServer server = new DatagramServer();
45.server.start();
46.}
47.}

클라이언트는 마찬가지로, DatagramSocket과 DatagramPacket을 이용하여 데이터를 전송하며 순서는 다음과 같습니다.

1. DatagramSocket 생성 ; 생성 시, Packet을 전송할 Server IP, PORT 정보 전달
2. DatagramPacket 생성 및 데이터 입력 : 전송할 Packet을 생성하고, 데이터를 입력
3. DatagramSocket.send 호출 : 전송할 Packet을 send method로 전송

간단한 클라이언트 소스는 다음과 같습니다.

01.import java.io.IOException;
02.import java.net.DatagramPacket;
03.import java.net.DatagramSocket;
04.import java.net.InetAddress;
05.import java.net.SocketException;
06.import java.net.UnknownHostException;
07.
08.public class DatagramClient extends Thread {
09.
10.public DatagramClient() {
11.super();
12.}
13.
14.public void run() {
15.try
16.{
17.while (true)
18.{
19.// 전송할 데이터 : 현재 시간
20.String data = String.valueOf(System.currentTimeMillis());
21.
22.// 전송할 DatagramPacket 생성
23.DatagramPacket packet = new DatagramPacket(data.getBytes(), data.getBytes().length, InetAddress
24..getByName("127.0.0.1"), 9999);
25.
26.// DatagramSocket 생성
27.DatagramSocket socket = new DatagramSocket();
28.
29.// DatagramPacket 전송
30.socket.send(packet);
31.}
32.} catch (UnknownHostException e)
33.{
34.e.printStackTrace();
35.} catch (SocketException e)
36.{
37.e.printStackTrace();
38.} catch (IOException e)
39.{
40.e.printStackTrace();
41.}
42.}
43.
44.public static void main(String args[]) {
45.DatagramClient client = new DatagramClient();
46.client.start();
47.}
48.}

Output :

received length : 13, received data : 1256179996593
received length : 13, received data : 1256179996593
received length : 13, received data : 1256179996609
received length : 13, received data : 1256179996609
received length : 13, received data : 1256179996609
received length : 13, received data : 1256179996609
received length : 13, received data : 1256179996609
received length : 13, received data : 1256179996609
received length : 13, received data : 1256179996609
received length : 13, received data : 1256179996640
received length : 13, received data : 1256179996640
received length : 13, received data : 1256179996640
received length : 13, received data : 1256179996640
저작자 표시