오라클 10g express의 8080 포트 변경하기

Posted 2007. 7. 23. 00:06 by alice201405

오라클 10g express 버전을 인스톨하면 자동으로 8080 포트를 데이터베이스  htmldb 웹 페이지를 위한 포트로 할당 된다.
이것을 바꾸려면 아래와 같이 한다..

1) 현재 포트 번호 확인

SQL> select dbms_xdb.getHttpPort() from dual;

DBMS_XDB.GETHTTPPORT()
----------------------
                  8080

인지하다 시피 8080 포트가 디폴트 웹서버 포트이다.이것을 아래와 같이 수정한다
sqlplus 에 system 유저로 로긴해서,

SQL> exec dbms_xdb.sethttpport(9090)

PL/SQL procedure successfully completed.



출처:http://abraxas73.springnote.com/pages/366782

WEB 2.0

Posted 2006. 3. 21. 15:45 by alice201405





앞으로 우리가 사용하게될 인터넷 혹은 웹대한 방향성을 제시한 일종의 패러다임이다.

그렇다면 기존의 Web을 'Web1.0'이라고 하겠는데 과연 이 Web2.0과 그것과는 무엇이 다른가?





1. Web2.0은 새로운 기술이 아니다. Web 환경의 변화의 방향을 제시한 것이다.



지난 2005년 샌프란시스코에서 Web2.0 컨퍼런스가 열렸다. 가장 사람들에게 의문점을 안겨준 것은 바로 'Web2.0'이라는 단어다. 이 Web2.0은 새로운 기술도 아니고 새로운 표준도 아닌 앞으로 Web 변화할 혹은 추구하게 될 최종 종착지에서의 모습을 말한다.



맨 처음 Web 등장했을 때는 간단한 이미지와 텍스트로 이루어진 정보가 대부분이었다. 막강한 인터넷 산업의 발전을 등에 업은 Web 이미지나 텍스트외에 다양한 포맷의 문서, 동영상, 파일등을 주고 받을수 있는 사용자 공간으로 변모했다.



하지만 Web2.0은 여기서 더 나아간다.

예를 들어, 현재도 그렇게 하고 있지만, 인터넷 온라인 영화를 본다고 했을 경우 Web을 통해서 실시간으로 영화감상을 할수 있다. 이 순간에 Web이라는 것이 영화플레이어로 변모하는 것이다. 또 다른 가능성은 Web을 통해 문서를 편집하는 것이다. 현재는 각종 워드프로세서 프로그램을 운영체제에 설치해야 하지만 Web2.0환경에서는 Web을 통해서 워드프로세서를 제공하는 싸이트에 접속하면 얼마든지 워드 작업을 할수 있다. 이 뿐아니라 음악감상을 하고 싶으면 음악을 심지어 그래픽 작업도 웹에서 이루어지길 기대한다.





2. 데스크탑과 Web의 경계를 허물다.



Web2.0은 위의 예제와 같이 데스크탑이라는 컴퓨터 분야를 집어 삼킬지도 모른다. 결정적으로 운영체제 자체가 없어질도 모른다. 간단히 인터넷이 되는 TV 에서 모든 것을 할수 있을지도 모른다. 웹서핑, 영화, 음악, 워드, 그래픽등 모든것이 Web으로 통하는 것이 Web2.0이다.



이렇게 되면 컴퓨터의 한분야인 데스크탑분야는 사라질 것이며 거기에 의존하는 많은 기업들이 쓰러질 것이다. 또한 보다 쉽게 임베이딩이 될지도 모른다. 조그마한 PDA에서 고품격의 워드프로세서 작업을 하게 될지도 모른다.





3. Web2.0을 위한 기술들, 아키텍쳐의 병합, 그리고 표준.



Web2.0을 위한 기술들 중에서 현재 와 닫는 것이 Weblog, RSS, Wiki, Ajax 등과 같은 것이다. Weblog 줄여서 Blog라고 하는 것은 이 시대를 이끌 새로운 대표 단어로 모두 인정하는 것이다. RSS는 보다 빠른 정보공유 또는 정보제공을 가능하게 해준다. Wiki는 기존의 게시판을 대체하는 어떤 주제에 대한 토론을 가능하게 해준다. Ajax는 표준 호환성 문제 개선에 선봉장이다.



이러한 Web2.0은 중심에는 표준이 자리하고 있다. 어떤 곳에서도 모두 동일한 성능과 표현, 구조등은 표준화된 스펙을 요구한다. 어떠한 웹이라라는 환경과 어떠한 아키텍쳐에서도 동일한 구조, 표현등을 위해서는 표준을 준수해야만 한다.



비단 이러한 것 외에도 Web을 통해서 소외받을수 있는 장애자나 노인, 어린이등을 위해서라도 표준화는 절실하다.





4. Web2.0 벌써 시작일지도... Web is Everthing

Web2.0은 뭔가 새로운 것이 아니다. 앞으로 그렇게 변모해야 할 목표다. 컴퓨터라는 기기에 의존하지 않고도 Web이라는 매체를 통해서 많은 것을 하게 됨으로써 이제 Web은 가정생활 속의 일부가 될지도 모른다. Web을 통해서 문서작업을 하고 영화를 보고, 음악을 감상하고 책을 읽게 될 그런 Web 환경.



모든 것은 웹으로 통하게 된다.

[ 아파치 2.0.55 + 톰켓 5.5 연동 하기 ]

Posted 2006. 2. 13. 14:59 by alice201405


[ 아파치 2.0.55 + 톰켓 5.5 연동 하기 ]

1.설치 프로그램 목록
->jdk 1.5.0_05 다운로드 (Tomcat 5.5.12 버젼은 JDK 1.5 버젼에서만 실행됨)
http://java.sun.com/j2se/1.5.0/download.jsp 에서 다운로드 하면 됨.
환경변수에서 시스템 변수에
변수이름: JAVA_HOME
변수값: C:\Program Files\Java\jdk1.5.0_03 (자바 설치시 디렉토리 지정)

->Apache HTTP Server 2.0.55 다운로드
http://ftp.apache-kr.org/httpd/binaries/win32/apache_2.0.55-win32-x86-no_ssl.msi

->Tomcat 5.5.12 다운로드
http://archive.apache.org/dist/jakarta/tomcat-5/v5.5.9/bin/

->Tomcat Connectors 다운로드
http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/win32/jk-1.2.15/
mod_jk-apache-2.0.55.so 파일을 다운 받는다.

2. 프로그램 설치
-> jdk 1.5.0_05 -> Apache HTTP Server 2.0.55 -> Tomcat 5.5.12

3.아파치 톰켓 연동 설정
(1)Apache 설정(Apache_Home->아파치 설치 디렉토리 폴더)
1.mod_jk-apache-2.0.55.so 파일을 Apache_Home/modules 폴더 안에 카피한다.
2.Apche_Home/conf 폴더 안에 httpd.conf 파일을 에디터로 연다.
a. LoadModule jk_module modules/mod_jk-apache-2.0.55.so 추가 한다.(173줄)
b. DocumentRoot "D:/Apache/tom" 자신이 쓸 홈디렉토리를설정한다.(228줄)
c. 위와 동일한 디렉토리를 지정한다.(253줄)
d. 파일목록을 보여부지 않기 위해 Options 옵션 뒤 Indexes FollowSymLinks 를 삭제 한다.(267줄)
e. index.jsp 를 자동으로 보여주기위해 DirectoryIndex 옵션에 index.jsp 를 추가한 다.(321줄)

f. 마지막에 아래의 구문은 전부 추가 한다.
아래의 구문중에 JkWorkersFile E:/Apache/Apache2/conf/workers2.properties 이부분은 자신의 아파치 홈폴더에 있는 conf 폴더 안에 workers2.properties 파일을 설정해 준다.
JkLogFile E:/Apache/Apache2/logs/mod_jk.log 이부분도 마찮가지로 자신의 홈폴더에 있는 log 폴더 안에 mod_jk.log 파일을 설정해 준다.




<-------------------------------여기부터---------------------------------->
# Where to find workers.properties
# Update this path to match your conf directory location (put workers.properties next to httpd.conf)
JkWorkersFile E:/Apache/Apache2/conf/workers2.properties
# Where to put jk logs
# Update this path to match your logs directory location (put mod_jk.log next to access_log)
JkLogFile E:/Apache/Apache2/logs/mod_jk.log
# Set the jk log level [debug/error/info]
JkLogLevel info
# Select the log format
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
# JkOptions indicate to send SSL KEY SIZE, set when servlet engine is Tomcat 3.2.x (on by default
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
# JkRequestLogFormat set the request format
# Options Description
# %b Bytes sent, excluding HTTP headers (CLF format)
# %B Bytes sent, excluding HTTP headers
# %H The request protocol
# %m The request method
# %p The canonical Port of the server serving the request
# %q The query string (prepended with a ? if a query string exists, otherwise an empty string)
# %r First line of request
# %s Request HTTP status code
# %T Request duration, elapsed time to handle request in seconds '.' micro seconds
# %U The URL path requested, not including any query string.
# %v The canonical ServerName of the server serving the request
# %V The server name according to the UseCanonicalName setting
# %w Tomcat worker name
JkRequestLogFormat "%w %V %T"
# Send everything for context /examples to worker named worker1 (ajp13)
JkMount /examples/* worker1
# send all requests ending in .jsp to worker1
JkMount /*.jsp worker1
# send all requests ending /servlet to worker1
JkMount /*/servlet/ worker1
<-------------------------------여기까지---------------------------------->


g. Apche_Home/conf 폴더 안에 workers2.properties 이름의 파일을 새로만든후 아래 구문 을 넣고 저장한다.
<-------------------------------여기부터---------------------------------->
# Define 1 real worker using ajp13 worker.list=worker1 # Set properties for worker1 (ajp13) worker.worker1.type=ajp13 worker.worker1.host=localhost worker.worker1.port=8009 worker.worker1.lbfactor=50 worker.worker1.cachesize=10 worker.worker1.cache_timeout=600 worker.worker1.socket_keepalive=1 worker.worker1.reclycle_timeout=300
[logger] level=DEBUG
[config:] file=${serverRoot}/conf/workers.properties debug=0 debugEnv=0
[uriMap:] info=Maps the requests. Options: debug debug=0
[shm:] info=Scoreboard. Required for reconfiguration and status with multiprocess servers file=${serverRoot}/logs/jk2.shm size=1048576 debug=0 disabled=00
[workerEnv:] info=Global server options timing=1 debug=0
[lb:lb] info=Default load balancer. debug=0
[channel.socket:localhost:8009] info=Ajp13 forwarding over socket port=8009 host=127.0.0.1 debug=0 tomcatId=localhost:8009
[ajp13:localhost:8009] channel=channel.socket:localhost:8009
[status:] info=Status worker, displays runtime informations
[vm:] info=Parameters used to load a JVM in the server process JVM=${JAVA_HOME}/jre/bin/client/jvm.dll classpath=${CATALINA_HOME}/bin/tomcat-jni.jar classpath=${CATALINA_HOME}/server/lib/commons-logging.jar #OPT=-Djava.class.path=c:\Program Files\Apache Group\Tomcat4.1\bin\tomcat-jni.jar OPT=-Dtomcat.home=${CATALINA_HOME} OPT=-Dcatalina.home=${CATALINA_HOME} OPT=-Xmx128M #OPT=-Djava.compiler=NONE disabled=0
# Uri mapping [uri:localhost/*.jsp] worker=ajp13:localhost:8009
[uri:www.test.com/*.jsp] worker=ajp13:localhost:8009
[uri:www.test.com/servlet/*] worker=ajp13:localhost:8009
[uri:/jkstatus/*] info=Display status information and checks the config file for changes. group=status:
[uri:/examples] info=Example webapp in the default context. context=/examples debug=0
[uri:/servlet/*] info=Servlet mapping
[uri:/*.jsp] info=Jsp mapping
<-------------------------------여기까지---------------------------------->

(2)Tomcat 설정(Tomcat_Home->톰켓 홈 디렉토리)
1.Tomcat_Home\conf 폴더에 있는 web.xml 파일을 에디터로 연다.
a. servlet 주석을 풀어준다. (92줄) invoker org.apache.catalina.servlets.InvokerServlet debug 0 2
b. servlet-mapping 주석을 풀어준다. (322줄) invoker /servlet/*
c. listings 의 param-value 를 false 로 수정 (63줄) default org.apache.catalina.servlets.DefaultServlet debug 0 listings false 1
2. Tomcat_Home\conf 폴더에 있는 jk2.properties 파일을 에디터로 연다.
a. handler.list=apr,request,channelJni 를 handler.list=apr,request 로 수정 b. shm.file=${jkHome}/work/jk2.shm 주석을 풀어줌. c. apr.jniModeSo=inprocess 의 주석을 풀어줌.

3. Tomcat_Home\conf 폴더에 있는 server.xml 파일을 에디터로 연다.
a. 주석 처리 (124줄)
b. 주석을 풀어줌. (120줄)
c. 주석 처리 (76줄)
d. webapps 는 Tomcat 의 Default DocumentRoot 임. 이것을 수정하기 위해서는 webapps 에 '/' 경로를 넣을 수 있음. 수정 (191줄)
e. path 는 default 로 "" 임. docBase 는 default 로 ROOT 임. documentRoot 를 바꾸기 위해 설정. 삽입 (196줄 정도)
docBace 안에 자신이 사용할 홈폴더를 지정한다. 아파치에서 사용한 홈폴더와 동일.

(3)실행
톰켓 재실행 -> 아파치 재실행
http://localhost 접속
톰켓 인덱스 화면이 뜨면 성공!!!

과연 xml 이 왜 유용한건가요?

Posted 2005. 10. 13. 15:52 by alice201405
자바 서비스넷에서 가져온 내용입니다.

저도 종종 xml을 쓰면서도 정규화된 개념으로 왜 좋은가라고

생각해 본적이 없었네요.

==========================================================
제목 : 과연 xml 이 왜 유용한건가요?
글쓴이: 이호준(silnoon0) 2005/10/06 13:03:51 조회수:408 줄수:8
안녕하세요.개발자로 들어선지 1년밖에 안된 아직 먼길을 가야하는 초보 프로그래머입니다.
프로젝트를 몇개 진행하다가 보면서, 조금씩 배워가고 있는데요
저는 프로젝트 내에서 XML은 단지, 설정파일로만 사용을 했습니다.
근데 예전부터 지금까지 쭈~욱 xml에 관심을 많이 가지시는것 같아서요.(제 생각입니다.)
과연 xml을 이용하면 뭐가 유용해질 수 있으며, 또한 어디에 적용을 할 수 있는지
너무나 궁금합니다. 무엇이든 그렇겠지만, 목표의식이 뚜렷해야 공부할 맛이 나는데요,
전 아직 xml이 왜 중요한지 또 왜 써야 하는지를 잘 몰라서 계속 인터넷만 헤매이고 있습니다.
경험 많으신 선배님들의 조언 부탁드립니다.감사합니다.^^
제목 : Re: 과연 xml 이 왜 유용한건가요?
글쓴이: 서민구(guest) 2005/10/12 22:36:58 조회수:60 줄수:55
저는 경험은 별로 없지만, 며칠간 아무도 답글을 안달고 계시길래..

일단 XML은 하드웨어/소프트웨어 독립적인 데이터 저장 방법이라는데
의미가 가장 크죠. 덕분에 여러가지 프로그래밍 언어를 써도, 여러가지
운영체제를 써도 데이터를 공유할 수가 있게 되었구요..

그 덕에 웹서비스 같은데서도 어떤 메소드를 어떻게 던지고 파라미터는 뭐고
내가 부를 메소드는 어디에있지 찾아보는데도 XML이 쓰일 수 있죠.
이기종 환경에서 그렇게 다 통할 수 있는 포멧은 역시나 XML이기 때문에요.

설정파일의 경우에는, 설정과 코드를 분리해서 저장하고 코드는 내버려두고
설정만 고치면 좋겠다.. 라는 건데, 그나마도

db.server = localhost
db.port = xxxx
db.user_id = xxxx
db.password = yyyy
mail.server = localhsot
mail.port = xxxx

와 같이 다 왕창 넣어버리던걸

<db>
  <server>localhost</server>
  <port>xxx</port>
  <user_id>xxxx</user_id>
  <password>xxxx</password>
</db>
<mail>
  <server>localhost</server>
  <port>xxxx</port>
</mail>

과 같이 써주면, 일단 전용 프로그램이 아닌데서도 쉽게 편집가능한데다가
사실 '사람'이 읽기에도 후자의 형태가 편하죠...

그런데 설정 파일의 경우에는 요즘엔 또 난데없이 "annotation이 더 좋아요~"라는
추세로 조금 바뀌는 듯 하네요. EJB의 새버젼에서는 정말 끝내주던데요..

사실 별로 맨날 바꾸는 것도 아닌 설정 내용을 별도의 XML로 해놓으면,
사실 사람이 읽기에는 쉽다고 앞에 써두긴 했지만, 길어지면
실은 읽기 어렵거든요. (아 이랬다 저랬다 죄송 ^^. 양면성이 있단 거죠..)

그 길고 긴 XML 내용을 잘 읽어서, 
클래스는 어디 com.xxxx.yyyy.aaaa.bbbb 이고 그 클래스의 파라미터 
zzz 는 1이구나 라는걸 XML보고 알 수야 있지만 정작 또 그 클래스에대한
소스를 열고나면 '아 근데 zzz가 얼마였지?' 라고 또 헷갈리고.. 

하나 고치려니 XML도 고쳐야되고 소스도 고쳐야되고. 그게 과연편한거 맞아?
라는 의문이 들어서 annotation으로 가는게 아닐까라고 생각이 듭니다..


말이 길었는데, XML은 데이터 저장 및 표현의 표준이라고 생각하시면 될 듯..

제목 : Re: 역시 강점은 표준이라 생각합니다.
글쓴이: 김영근(naucika) 2005/10/13 11:23:05 조회수:8 줄수:48
여러장점이 있긴합니다만, 기본적인건 XML관련문서가 매우 많기 때문에 
그런 글들을 보시면 될것 같습니다.

이 표준화란 개념은 매우 강력하고 무서운(?) 개념입니다.
요즘 웹이 이렇게 고속으로 광범위하게 성장한 이유가 무엇일까요?
여러 다양한 웹브라우져가 있지만, 바로 이것들은 HTML 표준을 모두 따르기 때문입니다.
유닉스를 써도, 맥을 써도 웹페이지를 보는건 똑같죠? (물론 세부적인 내용이 다를순 있지만..)
XML은 이런 HTML의 미약한 부분을 보완한 (데이터 측면에서) 새로운 표준이라 보시면 될것 같습니다.

요즘 핸드폰 충전많이 하시죠? 예전엔 각사마다 서로다른 표준을 따라서, 심지어는
집에서 또 회사에서 사용할 충전기 또는 USB 케이블을 별도로 구입하곤 했죠.
요즘은 정통부 규격때문에, 어느집 놀러가도 왼만하면 충전이 거의 가능합니다.
표준인거죠?

예를들어, 어떤회사의 레포트 툴이 있다고하면 그 레포팅툴은 엔진은 C로 폼레이아웃은 
XML로 작성합니다. 이 XML규격만 맞춰주면 레포트가 출력되는 형식이죠. B사에서 
이 XML규격을 디자인해주는 자바 디자인툴을 만듭니다. 또, C사 D사 에서 서로다른 디자이너
툴을 만듭니다. 그래도 결과물은 XML 임으로 디자인툴에 상관없이 보여지는 내용은
같습니다. 게다, 만들어진 XML은 각 툴에서 서로 호환이 됩니다.

또, 요즘 RSS같은경우 이 표준화를 매우 잘 활용하고 있지 않습니까? 동일한 규격의 
데이터 폼을 제공해주면, 어떠한 홈페이지라도 한곳에서 모두 일괄 확인할수 있죠.
심지어는 블로그,위키,카페,홈페이지 전부 이 규격만 준수해주면 됩니다.

또, 웹서비스가 있죠? 바로 이런 XML의 강점으로 탄생한 수많은 기술들이 있습니다.
그 근간에는 바로 강력한 표준화란 정점이 있습니다.

어떠한 레거시와 OS와 각종언어에서도 호환되는 데이터를 이동시킬수 있다는것 만해도
정말 많은 제약을 벗어날수 있게 해줍니다.

물론 아직도 이 강력한 표준화는 진행중이라 말할수있겠지만, 
이제 곧! 입니다. 이전부터 있어왔던 XML이 근래에 대두되고 있는점은 바로 그 활용에
있습니다. 개념에서 끝나는게 아니라, 이젠 클라이언트들이 그걸 원하고 있고,
각종 서비스들이 덩치가 비대해지고, 기존 레거시들이 다양화되고, 
각종 벤더들이 본격적으로 지원하게 되면서 대두되기 시작한거죠.

설정파일에만 장점이 있는건 아닙니다.
사실 전 첨에 설정파일 나름대로의 문법(?)으로 만들어놓고 그걸 읽어드리는 로직을
만드는것도, 이 XML 을 이용하고, 파서를 이용하면서 매우 편해졌습니다.
내가 만든 파서도 모를때도 많던데요. -_-;

그외에도 많죠~~ 




온세상을 자바로~ -_-!!
http://cafe.naver.com/javalove

[패턴 정보] 예제로 설명한 Factory Method Pattern

Posted 2005. 9. 27. 10:15 by alice201405
Factory Method 패턴의 워크플로우


객체 지향 프로그램에서 계속해서 볼 수 있는 패턴 중의 하나는 Factory 패턴 또는 클래스이다. Factory 패턴은 제공된 데이터에 의존하는 여러 가능한 클래스 중의 하나를 반환하는 것이다. 일반적으로 반환되는 모든 클래스는 공통적인 부모 클래스와 공통적인 메소들을 가지지만, 그것들은 각각은 다른 일을 하고, 다른 종류의 데이터를 위해 최적화 되어진다. 그림에서 x는 상위 클래스이고 xy와 xz는 x로 부터 파생되었다. Factory는 입력된 인자에 의존하여 하위 클래스를 반환을 결정하는 클래스이다. 오른쪽에서 어떤 abc라는 값이 주어질 때의 getClass 메소드를 정의하였고, 이 메소드는 클래스 x의 인스턴스를 반환한다. 모두 같은 메소드를 가지고 있기 때문에 반환되는 getClass가 어떤 값을 반환하는가는 문제가 되지 않지만, 구현은 다르다. 어떻게 반환할 것인가를 결정하는 것은 전반적으로 Factroy에 의해서 이다.

구조


역할
1. Product(제품)의 역할
생성된 제품(인스턴스)가 가지고 있어야 할 인터페이스(API)를 결정하는 추상 클래스 구체적인 역할은 하위 클래스인 SpecificProduct 역할이 결정한다.

2. Creator(생산자)의 역할
Product 클래스를 생성하는 추상 클래스 Creator는 실제 제품을 생성하는 일을 하는 SpecificCreator 역할에 대해서는 아무것도 모른다.

3. SpecificProduct(구체적 제품)의 역할
구체적인 제품을 나타내는 클래스

4. SpecificCreator(구체적 생산자)의 역할
구체적인 제품을 만드는 클래스



의도

객체를 생성하는 인터페이스를 따로 정의한다. 그리고 생성되는 객체의 클래스를 결정하는 것은 하위 클래스에서 담당한다. 이 패턴은 어떤 클래스가 객체를 생성하는 일을 하위 클래스에게 위임한다.

적용시기
다음과 같은 상황에서 Factory 패턴을 고려할 수 있다.

1. 객체들에 대한 클래스의 종류를 예상 할 수 없을 때
2. 생성할 객체를 기술하는 책임을 서브클래스에 정의하고자 하는 경우
3. 객체 생성의 책임을 서브클래스에서 위임시키고 서브클래스에 대한 정보를 은닉하고자 하는 경우

예제소스


위 예제 소스의 내용은 클라이언트가 사용하는 UI형태가 KoreaUI, EnglandUI두 가지 형태가 있으며 각 UI에서는 htmlPrinter, textPrinter 두 가지 타입의 출력 양식을 가진다.

Printer 클래스는 구성에서 “Product”에 해당하며 UI 클래스는 “Creator”에 해당한다. \

Factory Mothod는 “getPrinter (String message, String textMode)”이다.

다음은 예제소스이다.
=================================================================
product 패키지
=================================================================
[CODE]package product; public class Printer { protected String message; public Printer() { } public String print() { return message; } } package product; public class htmlPrinter extends Printer { public htmlPrinter(String message) { super.message = " &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"+message+"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "; } } package product; public class textPrinter extends Printer { public textPrinter(String message) { super.message = "\n "+message+" \n"; } }[/CODE]

=================================================================
creator 패키지
=================================================================

[CODE]package concrete; import product.*; public abstract class UI { protected String header; protected String footer; protected String DecoTitle; public UI(String title) { DecoTitle = title; } protected void setHeader() { header = "Start Print...... "+DecoTitle; } protected void setFooter() { footer = DecoTitle+"........ End Print"; } public String print(String message, String textMode) { setHeader(); setFooter(); StringBuffer buffer = new StringBuffer(); buffer.append(header); buffer.append(getPrinter(message, textMode).print()); buffer.append(footer); return buffer.toString(); } public abstract Printer getPrinter(String message, String textMode); } package concrete; import product.*; import product.Printer; public class KoreaUI extends UI { public KoreaUI(String title) { super(title); } public Printer getPrinter(String message, String textMode) { if(textMode.toUpperCase().equals("HTML")) return new htmlPrinter(message+" 대한민국"); else return new textPrinter(message+" 대한민국"); } } package concrete; import product.*; import product.Printer; public class England extends UI { public England(String title) { super(title); } public Printer getPrinter(String message, String textMode) { if(textMode.toUpperCase().equals("HTML")) return new htmlPrinter(message+" England"); else return new textPrinter(message+" England"); } }[/CODE]


=================================================================
클라이언트 프로그램
=================================================================

[CODE]import concrete.*; public class mainClass { UI ui = null; public mainClass() { } public void setUI(String title, String contry) { if(contry.toUpperCase().equals("KOREA")) ui = new KoreaUI(title); else if(contry.toUpperCase().equals("ENGLAND")) ui = new England(title); } public void exec(String message, String textMode) { System.out.println(ui.print(message, textMode)); } /** * * @param args */ public static void main(String[] args) { mainClass client = new mainClass(); if(args.length != 4) { System.out.println("예) java mainClass [타이틀] [출력메세지] [korea or england] [html or text]"); System.exit(0); } client.setUI(args[0], args[2]); client.exec(args[1], args[3]); } }[/CODE]

=================================================================
관련패턴

1. Factory Method 패턴은 Template Method 패턴에서 발전된 형태이다.
2. Abstract Factory, Builder 패턴에서 참조

[패턴 정보] Creational Patterns(생성 패턴)

Posted 2005. 9. 23. 14:55 by alice201405
모든 Creational Patterns은 객체의 인스턴스를 생성하는 최상의 방법과 관련이 있다. 이것은 작성된 프로그램이 생성되고 배치된 객체들과 의존적이지 않아야 하기 때문에 중요하다. 자바에서는 가장 간단한 방법으로 new 연산자를 이용하여 객체들의 인스턴스를 생성하는 방법이다.

Fred = new Fred() ; -> instance of Fred class

그러나 이 방법은 프로그램 안에서 생성된 객체가 의존적이어서 결국 코딩이 어렵게 된다. 많은 경우에, 생성된 객체의 정확한 본질은 프로그램의 요구에 의하여 변경되어 질 수 있고, "createor"라는 특수한 클래스로의 추상화 과정은 프로그램을 보다 유연하고 일반적으로 만들 수 있게 한다.

패턴이름

내용

Factory Method

Factory 패턴은 제공되는 데이터에 의존하는 추상 기저 클래스의 가능한 하위 클래스들 중의 하나를 반환하는 간단한 의사 결정 클래스를 제공한다.

Abstract Factory Method

Abstract Factory 패턴은 생성할 인터페이스를 제공하고, 관련된 객체들의 여러 군 중에서 하나를 반환한다.

Singleton Pattern

Singleton 패턴은 오직 하나의 인스턴스만을 갖는 클래스이다. 그 것은 생성된 인스턴스에 접근하는 하나의 포괄적인 점을 제공한다.

Builder Pattern

Builder 패턴은 단지 객체에 대한 형태와 내용만 지정함으로써, 복잡한 객체를 구성 할 수 있다. , 각각의 객체 구성에 대한 모든 정보를 자세히 알고 있지 않아도 쉽게 객체를 구성 할 수 있다.

Prototype Pattern

Prototype 패턴은 어떤 객체의 생성 방식에 대한 자세한 정보를 모르더라도 그 객체가 원하는 다른 객체를 생성할 수 있도록 도와준다. 우선, 생성하려는 객체에 대한 프로토타입 객체를 미리 제공한 다음, 프로타입 객체의 복사본을 생성함으로써 원하는 대상 객체를 만들게 된다.

[패턴 정보] What Is a Pattern?

Posted 2005. 9. 23. 14:50 by alice201405

What Is a Pattern?

반복되는 공통적인 문제에 대하여 가장 적절한 해결책을 제시하는 것

 

 

Benefits of Patterns(패턴의 이득)

·         디자인 문제점을 토론하기 위한 높은 레벨의 언어를 제공한다.

·         디자인 문제의 해결책을 제공한다.

·         패턴의 조합은 재사용할 수 있는 아키택쳐를 제공 한다.

 

 

디자인 패턴을 적용할 때 제일 중요한 세가지 규칙

·         구현 클래스가 아니라 인터페이스를 가지고 프로그래밍한다. à 인터페이스를 바탕으로 하는 클래스 호출

·         상속(inheritance)이 아니라 위임(delegation)을 주로 사용한다.

·         Coupling을 최소화함으로써 추후의 변화를 국부화 한다. à 어느 하나의 기능 변화가 전체 클래스 구조를 바꾸거나 혹은 많은 부분에 걸친 변화를 야기한다면 디자인이 초기부터 잘 못 되어진 거라 할 수 있다. 디자인 패턴의 기본중에 기본은 “coupling을 최소화함에 있다.

 

 

디자인패턴 카탈로그 기술 형식


       name(이름) : 패턴의 이름은 패턴 자체의 내용을 효과적으로 전달할 수 있어야 한다.

       Classification(종류) : 여러 개의 패턴들을 체계적으로 분류한다. (: 생성, 구조, 행위)

       Intent(의도) : 이 패턴이 무엇을 하며 어떤 의도로 작성되었으며 무슨 문제를 해결하는 지를 설명하는 간단한 문장

       Motivation(동기) : 이 패턴이 해결해야 하는 디자인 문제와 그것을 해결하기 위해 클래스와 객체들이 어떻게 사용되는지에 대해 시나리오 형식으로 기술함

       Applicability(적용시기)

       Structure(구조) : 패턴에서 문제를 해결하기 위해 사용되는 클래스와 객체의 구조 UML 1.2 다이어그램을 통해서 일반적으로 표현한다.

       Participants(구성물) : “구조항목에 포함된 각종 클래스와 객체의 의미와 그 책임을 설명

       Collaboration(협력관계) : 각 클래스와 객체가 자신에게 맡겨진 책임을 수행하기 위해 서로 메시지를 주고 받는 과정을 묘사함.

       Consequence(결과) : 패턴이 목적을 달성하기 위해 어떤 면을 해결하는 지를 설명하고 패턴을 적용할 때 발생할 수 있는 문제점과 패턴적용시의 효과, 시스템 상황에 따라서 변동하는 부분들을 기술

       Implementation(구현) : 패턴을 구현할 때의 고려사항과 힌트, 함정, 테크닉등과 프로그래밍 언어 별로 주의해야할 점들을 기술

       Sample Code(예제코드) : 특정 프로그래밍 언어로 패턴을 구현한 예제를 보임

       Known Uses(알려진 사례) : 실제로 사용되는 시스템에서 발견되는 패턴의 예제를 기술

       Related Patterns(관련 패턴) : 본 패턴과 유사하거나 밀접하게 관련된 다른 패턴을 기술

[패턴 정보] MVC 모델과 Observer 패턴

Posted 2005. 9. 22. 09:39 by alice201405
저자: 김대곤



이 패턴을 설명하기 전에 MVC 모델을 먼저 살펴보자. MVC 모델은 조금은 거창하게 알려져 있는 듯하다. 거의 그런 경우가 드물지만, 몇 년 전 필자가 본 누군가의 이력서에는 자신의 강점을 프로젝트에 MVC모델을 적용한다는 것이라고 적혀 있는 걸 보았다. 필자가 보기에 MVC 모델을 적용한다는 것은 달리기를 한다는 말과 같아 보인다. 필자도 달리기를 한다. 그러나 잘 하지는 못한다. 국민학교(초등학교)때부터 체육은 언제나 주저하게 되는 분야였다. 달리기를 잘하는 것과 달리기를 하는 것은 다른 문제이다.

MVC 모델에서 MVC는 각각 Model, View, Control를 말한다. Model은 데이터 또는 기본 기능을 말하고, View는 유저 인터페이스를 말한다. 이 두가지는 시스템 개발에 있어서 없어서는 안되는 부분이며, 누가 개발을 하더라도 반드시 있기 마련이다. MVC 모델은 C 모델이라고 불러도 상관없을 만큼 한마디로 말해서 Control이라는 레이어 계층을 두자는 것이다. Graphical User Interface를 사용할 때, Model 계층과 View 계층 사이에 Control 계층을 만들어서 사용하자는 것이다. 왜 그렇게 해야 하는가? 여기에는 몇가지 가정이 담겨 있다.

두 계층 사이에 필수적이지 않은 다른 계층을 두는 이유는 간단하게 말해서 두 계층이 직접적으로 Coupling되는 것을 피하려고 하기 때문이다. 즉, Control 계층은 Model 계층과 View 계층의 high Coupling을 막아준다. Model 계층과 View 계층의 high coupling이 좋지 않은 이유는 Model과 View의 생명주기가 다르기 때문이다. 일반적으로 Model 계층의 생명주기가 길며, 변경이 드물게 일어난다고 여겨진다. 예를 들어, 물건을 파는 웹 사이트에서 사이버 매장을 새 단장하는 경우를 생각해 보자. 일반적으로 View만 바뀌지 Model은 바뀌지 않는다. 같은 기능을 가진 시스템에서 사용자에 따라서 다른 View가 존재할 수도 있다. 또는 웹사이트에서도 보고, PDA에서도 보는 경우도 같은 Model이 서로 다른 View로 표현되는 예라고 할 수 있다. 직접적인 Coupling은 Model과 View를 같이 바뀌도록 만든다. 이것을 Control 계층이 막아준다. 그럼 View가 바뀌면 Control이 바뀌어야 하는 것이면 마찬가지 아닌가 하는 의문이 생긴다. Control 계층의 로직은 매우 간단한다. 아니 간단하게 설계해야 한다. 적어도 Model를 바꾸는 것보다 훨씬 쉽게. Control 계층은 단지 Coordinator에 불과해야 하기 때문이다.

MVC 모델은 Layered Style이고 Layered Style에서는 아래 Layer가 상위 Layer를 사용하는 것을 권장하지 않는다. A 계층이 B 계층을 사용하게 되면, A 계층은 B 계층에 종속된다. 즉, B 계층이 없으면 A 계층은 자신의 역할을 수행하지 못하는 것이다. B 계층은 A 계층이 없어도 문제가 없다. 이러한 의존관계를 Usage dependency 라고 부른다. Layered Style에서 상위 계층은 하위 계층에 대해 Usage dependency가 있다. 하위 계층이 더 생명주기가 길며, 변경되는 일이 적어야 한다. 그런데 하위 계층이 상위 계층에 있는 기능을 사용하면 하위 계층이 상위 계층에 종속되어 버린다. 만약, MVC 모델에서 Model이 View의 기능을 사용해야 하는 경우에 Model이 View에 종속되는 것을 어떻게 막을 것인가?

이것이 Observer 패턴을 사용하게 되는 중에 하나이다. 이제 Observer 패턴에 대해서 살펴보자. GoF의 디자인 패턴에는 Observer 패턴의 목적을 이렇게 정의하고 있다. "Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and update automatically." "한 객체의 상태가 바뀔 때 다른 객체들에게 그 사실을 알려주고 자동적으로 업데이트 되도록 하고자 한다면 이 패턴을 쓰시오" 정도 될 것이다. 좀 걸리는 단어는 one-to-many dependency다. 이제 하나씩 살펴보도록 하자.

한 객체의 상태에 변화가 생기면, 그 객체의 상태에 관심있는 객체들에게 알려주는 방식이다. 객체에게 무엇인가를 알려주는 방법은 객체의 메소드를 통해서 이다. 관심 있는 객체의 메소드를 호출해주면 된다. 하지만 객체의 메소드를 사용하면, 이 객체에 대해 usage dependency가 생기게 된다. 즉, coupling이 높아진다. 이 패턴은 특정한 알려주는 방식을 제안하고 있다.

이 패턴이 어떻게 작동되는지 살펴보자. 예제 파일[Download]을 실행해 보자. 아래의 두 화면이 보인다. Input data 에 데이터를 입력하면 Observer 화면에 나타나도록 되어 있다.







"Subject.java"에 있는 Vector 데이타가 바뀔 때 자동적으로 바뀐 내용을 보여주려고 한다. Subject 객체가 Observer객체의 내용을 바꾸기 위해서는 Observer객체의 메소드를 호출해야 하고, 메소드를 호출하기 위해서는 그 객체의 Reference가 필요하다.

Subject 객체의 addObserver라는 메소드를 통해 Observer는 자신의 Reference를 제공하고, Subject는 Observer 객체(MyFrame.java)의 update(Vector v) 메소드를 통해 화면을 바꾸어 준다. 별 무리 없이 작동하고 있다. 문제점은? MyFrame 클래스를 삭제해 보면 알게 된다. Subject 클래스가 더 이상 컴파일 되지 않는다. 이유는 간단하다. 자신의 Observer였던 MyFrame 클래스를 소스안에 포함하고 있었기 때문이다. 만약, 객체의 상태에 관심을 가지고 있는 객체가 오직 하나이고, 변경될 소지가 적다면, 위와 같이 코딩해도 별 문제는 없을 것이다. 하지만 Observer가 한 개가 아니라 20개 정도 되면 20 개나 되는 타입의 클래스를 포함하고 있게 된다. 그 중에 updata(Vector v)라는 메소드를 가지고 있지 않은 클래스라도 있으면 그건 바로 에러가 된다.

이러한 문제를 해결하는 방법은 Subject가 각 Observer들의 클래스 타입 대신 인터페이스를 사용하고, 이 인터페이스는 자신을 구현하는 클래스들에게 update(Vector v)라는 메소드를 구현하도록 강제한다. [Download]

코드를 자세히 살펴보면, 이 Observer 패턴과 자바의 이벤트 처리가 같음을 알 수 있다. 리스너(ActionListener)를 만들고, 리스너를 Subject(JButton)에 등록하고 JButton의 상태가 변하면 ActionListener로 강제된 actionPerformed 메소드가 호출된다. 이 패턴도 Observer 인터페이스를 구현하는 객체를 만들고, 만든 객체를 Subject에 등록하고, Subject 객체는 자신의 상태가 바뀌면, 인터페이스에 정의된 메소드를 호출한다. 즉 Observer 패턴은 이벤트 시스템을 구현할 때 사용된다. 이벤트 시스템의 구현은 Observer 패턴이 주는 또 하나의 강점이다.

하지만 기본은 전혀 바뀌지 않았다. 객체에게 무엇인가를 알려주는 방식은 메소드이고 메소드의 호출을 위해서는 객체의 Reference가 필요하는 것. 조금 다른 방식일 뿐 이 두가지 작업은 패턴을 적용해도 피할 수 없는 것이다. 즉, 패턴은 어떤 문제들을 교묘히 피해가는, 평소에는 잘 생각나지 않는 방법을 알려주고 있다. 그래서 패턴을 언제 사용하는가에 대한 이해는 외우지 않고 있으면 잘 생각나지 않고, 사용하지 않으면 이해되지 않는 측면이 있다. 패턴은 처음 적용해 볼 때 가장 어렵다. 한 번 하고 나면 생각만큼 어렵지는 않다.

필자의 패턴 설명은 전체적으로 모든 내용을 다루고 있진 않다. 일반적으로 Subject는 attach(Obsever obs), detach(Observer obs), notifyAll() 이라는 메소드를 가지고 있다. 하지만 detach 메소드는 다루지 않았다. 인터페이스가 강제하는 메소드도 여러 형태가 될 수 있으며, 그 메소드에 내용이 전달되지 않고 Subject의 다른 메소드를 호출함으로 Subject의 상태를 가져오기도 한다. 자세한 사항은 Design Pattern 책을 참고하기 바란다. Jstorm(www.jstorm.pe.kr)에서도 Design Pattern에 관련된 자료들을 찾을 수 있으리라 생각된다.


 


출처 : http://network.hanbitbook.co.kr

[패턴 정보] Factory Method 패턴

Posted 2005. 9. 15. 11:06 by alice201405
Factory Method 패턴
저자: 김대곤  출처 : 한빛네트워크(http://network.hanbitbook.co.kr)

필자는 지난 번 기사(GRASP 패턴)에서 Singleton 패턴이 Factory Method 패턴을 구현하고 있다고 했는데, 그것은 잘못된 표현이다. 실제로 Singleton 패턴은 Factory Method 패턴을 구현하고 있지 않다. 이런 착각은 필자가 패턴을 이해할 때, 그것을 지나치게 단순화(Abstraction)시켜서 이해하기 때문이다. 필자에겐 Object의 생성을 담당하는 메소드가 있으면 모두 Factory Method 패턴을 구현하고 있는 것처럼 보이고, 항상 그렇다는 착각에 빠진다.

본 기사는 앞에 언급되었던 몇가지 주제들을 설명함으로서 Factory Method 패턴이 직면하는 상황이 왜 발생하는지를 제시할 것이다. Factory Method 패턴 자체는 별로 어려워 보이지 않는다. 그런데 좀처럼 패턴을 사용해야 하는 상황을 만나지 못하는 것이 이 패턴을 이해하는데 가장 큰 걸림돌이 아닐까 생각한다. 그러므로 패턴 자체에 대한 설명은 독자의 몫으로 남겨두고자 한다.

Abstraction

필자는 패턴을 단순화(또는 추상화 Abstraction)시켜서 이해한다고 말했다. Gang of Four의 Design Patterns에는 "Consequences", "Implementation"라는 소제목들이 등장한다. 하지만 필자는 거의 읽어본 적이 없고, 관심도 없다. 그러므로 필자에게 패턴이라는 단어와 "Consequences"나 "Implementation"이라는 단어와 연관되지 않는다. 이렇듯이 관심사항이 아닌 것을 제거해버리는 것을 추상화(Abstraction)이라고 할 수 있다.

Factory Method 패턴이 Object가 생성되어야 하는 시점은 알고 있으나 어떤 Object가 생성되어야 하는지 알 수 없을 때, 객체의 생성을 Subclass에 위임하는 방식으로 문제를 해결할 수 있다고 말하고 있다. 첫 번째 질문은 왜 이런 상황에 직면하게 되었는가이다. 어떻게 이런 일이 발생할 수 있는가? 그것은 여러 종류의 객체를 추상화(Abstraction)시켜서 사용했기 때문이다.

게임의 예를 들어보자. 이 게임은 병사와 탱크를 가지고 전투를 하는 게임이고, 병사와 탱크를 만들기 위해서 병사를 만들어 내는 막사와 탱크를 만들어 내는 공장이 있어야 된다. 게임의 기능은 "생성", "공격", "이동"이 있다. 생성의 기능을 자세히 살펴보자. 게임상에 존재하는 어떤 물체를 선택하고 "생성" 버튼을 눌렀다고 가정하자. 먼저 선택한 물체가 생성이라는 기능을 가지고 있는 객체인지를 확인하고, 막사이면 병사를 공장이면 탱크를 만들어야 한다. 만약, 실제 객체(막사와 공장)을 사용하였다고 가정하자. 그런데 비행기를 만드는 새로운 공장이 생기면 생성 기능은 수정되어야 한다. 선택한 객체가 새로운 공장인지를 체크해야 하고, 새로운 공장이면 비행기를 만들어야 하기 때문이다. "생성"이라는 기능의 입장에서는 그게 막사인지, 공장인지, 아니면 새로운 공장인지는 관심의 대상이 아니다. "생성" 기능의 입장에선 오직 선택한 객체가 "생성"이라는 기능을 가지고 있는가만 알면 된다. 실제로는 존재하진 않지만 생성이라는 기능을 가진 것들을 Factory라는 개념으로 추상화하여 사용하면, 빈번한 수정과 High Coupling을 피할 수 있다. 객체의 종류에 따라 행동양식이 바뀌는 경우, 조건문을 사용하지 말고 다형성(Polymorphism)를 사용하라는 GRASP 패턴의 "Polymorphism" 원칙을 적용하여 Interface를 만들어서 생성 기능안에서는 Factory Interface만 사용하고 실제 객체들은 Factory Interface 타입의 변수 안에서 모두 숨겨진다. 새로운 공장이 만들 때 Factory Interface만 구현하면 "생성"버튼의 코드는 전혀 수정될 필요가 없다.

"생성" 기능 버튼을 사용자가 클릭하면, 객체를 생성해야 한다. 시점은 알지만 어떤 객체가 생성될 것인지는 선택되는 객체에 따라서 다르다. 그러면 당연히 Factory 객체는 객체의 생성을 담당하는 메소드(병사, 탱크, 비행기 등을 만들어야 함으로)를 가지고 있어야 한다. 이것이 Factory Method 패턴이 직면하는 상황인 것이다. 사실 이 문제는 객체의 생성 뿐 아니라 일반적인 행동(메소드)도 마찬가지이다. "이동" 기능에 대해서 생각해보라.

객체 생성을 (생성자가 아닌) 메소드를 통해서 하고자 하는 이유

실제 코드 예제를 보기 전에 객체를 생성자가 아닌 메소드를 통해서 생성하려고 하는 이유에 대해서 살펴보자. 메소드를 통해서 생성한다는 것은 Singleton 패턴에 나오는 Singleton 클래스 또는 Static 메소드를 통한 자기 자신 타입의 객체 생성이 아닌 경우에는 객체를 자기 자신의 메소드가 아닌 다른 객체의 메소드 안에서 생성한다는 의미이다. GRASP 패턴에 나오는 Creator 패턴에서 설명했듯이 이런 경우 컨텍스에서 제공받아야 하거나 제약사항들을 체크할 수 있다. 어떤 객체가 Interface를 구현한 객체의 경우, Interface를 쓴 이유는 실제 객체를 숨기기 위해서 한 작업인데, 생성자를 통해서 하면 실제 객체가 드러나 목표하는 효과를 볼 수 없게 되기 때문이다.

너무나 유명하고, 흔한 예제

필자가 아는 선배는 글을 쓰거나 프리젠테이션을 할 때는 항상 예제를 제공하는 것이 기본적인 예의이지 원칙이라고 했다. 설명을 하면 어려운 것도 예제를 보면 쉽게 이해가 되기 때문이겠지만 사실 이해하기 쉬운 예제를 제공하는 것은 쉬운 일이 아니다. Factory Method 패턴은 너무 유명하고 흔해서 검색엔진으로 검색하면 금방 찾을 수 있다. 솔직히 말하면, 필자도 이 예제를 그런 방식으로 구했다. 1분 전에.

import java.sql.*;

public class JDBCExample {
private static String url = "";
private static String user = "";
private static String passwd = "";

public static void main(String args[]) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");

Connection connection = DriverManager.getConnection(url,user,passwd);
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("Select to_char(sysdate) from dual");

while (resultSet.next())
{
System.out.println("It is " + resultSet.getString(1));
}

resultSet.close();
statement.close();
connection.close();
} catch (Exception e) {
} finally {
}
}
}
몇 가지이 수정이 가해지지 않으면, 이 예제는 실행되지는 않을 것이다. 그러나 Factory Method 패턴을 사용한 클래스가 무려 2개나 된다. 그것도 연결해서 사용했다. Connection 객체는 createStatement() 메소드를 통해서 Statement 객체를 생성하고 Statement 객체는 executeQuery() 메소드를 통해서 ResultSet 객체를 생성하고 있다. Connection, Statement는 모두 Interface이다. 만약 실제 객체를 사용했다면 위의 코드는 다음과 비슷한 모습이 될 것이다.

public class OracleJDBC {

private static String url = "";
private static String user = "";
private static String passwd = "";

public static void main(String args[]) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");

OracleConnection connection = new OracleConnection(url,user,passwd);
OracleStatement statement = new OracleStatement();
OracleResultSet resultSet = statement.executeQuery("Select to_char(sysdate) from dual");

while (resultSet.next())
{
System.out.println("It is " + resultSet.getString(1));
}

resultSet.close();
statement.close();
connection.close();
} catch (Exception e) {
} finally {
}
}
}
위 코드는 실행되거나 컴파일이 되거나 하지는 않는다. 실제 오라클을 사용할 경우 쓰이는 객체들이지만 이렇게 코딩하는 사람은 없다. 만약 오라클 안쓰면 다 고쳐야 되는데 누가 이렇게 쓰겠는가? 위의 작업을 하는 사람들에겐 실제 무슨 객체가 쓰이는가는 관심사항이 아니다. 단지 어느 곳에 저장되어 있는 데이터를 읽어서 가져오는 것이 주요 목표인 것이다. JDBC는 각 데이터베이스들을 추상화했지만 더 높은 추상화를 적용한 JDO(Java Data Object)도 있다. JDO는 Persistence에 대한 추상화를 시도하고 있다.

결어

그럼 추상화(Abstraction)를 어떻게 할 것인가? 이런 문제는 아무도 설명해 주지 않는다. 필자도 누구에게서 추상화의 원리나 관련된 강의를 받은 적이 없다. 필자가 항상 염두에 두는 생각이 있다면 "내가 필요로 하는 최소한의 것만 받아들이겠다"는 자세이다. 누가 나에게 무언가를 요청한다면 "네가 좀 알아서 해 주면 안돼?"라고 말하는 자세 말이다.(실제로 이렇게 살면 맞아 죽겠지만 말이다.) 그렇게 해서 남은 최소한 것을 Interface로 정의해서 사용하자.

필자가 쓰고 있는 패턴에 관한 기사도 Design Pattern를 설명한다기 보다는 Design Pattern이라는 주제에 대해 버리고 버려서 남은, 비슷해 보이지만 전혀 다른 내용이 아닐까 생각한다. 필자는 상속을 좋아하지 않는다. 그래서 SubClass, SuperClass와 같은 용어보다는 Interface라는 용어를 많이 사용한다. 그러나 상속에 대해서도 적용될 수 있음을 밝혀두는 바이다.

[패턴 정보] Immutable 패턴

Posted 2005. 9. 9. 10:43 by alice201405
Immutable Pattern
JLab 편집실 blueduck (최성원)

한객체에 동시접속 오버헤드를 줄이고 레퍼런스를 같은 객체와 공유하여 객체의 견고함(robustness)을 증가시켜 주는 패턴입니다. 객체가 생성된 후에 객체 상태 정보가 빠귀는것을 허락하지 않으므로써 객체의 견고함(robustness)을 이룰수 있습니다. 또한, Immutable 패턴은 한 객체를 공유하는 멀티 쓰레드의 실행을 동기화하는 요구를 피합니다. 내용 여러 객체들에 의해서 사용되어지는 객체의 상태 정보 변경을 동기화하고, 상태정보가 전파되는 것을 막기 위해서 공유되는 객체를 immutable객체로 만들 수 있습니다. immutable객체는 객체가 생긴 후에는 어떠한 상태변화도 허락하지 않습니다. 이는 상태정보를 변경하는 메소드를 포함하지 않음으로써 구현할 수 있습니다. 멤벼 변수 값을 수정하는 set 메소드가 없어야 하는 것이겠지요.

immutable 클래스는 상태변화를 필요로 하지 않으며 여러 다른 객체들에 의해서 사용되어지는 클래스의 경우에 유용하며, 멀티쓰레드에 의해서 공유되는 객체의 상태를 일관성있게 유지해야하는 경유에 유용합니다. 멀티쓰레드에 의해서 공유되는 경우에는 멀티쓰레드의 실행을 동기화할 필요가 없으므로 동기화에 따르는 오버헤드를 줄일수 있으며, 객체의 robustness(견고함,강건함)를 증가시킬 수 있습니다.

immutable클래스를 구현하기 위한 요구사항으로는

 

* 생성자들을 제외하고 클래스의 멤버 변수 값을 수정하는 메소드(setter 메소드 등)가 없어야 합니다.
* 새로운 상태 정보를 생성하는 메소드는 새로운 인스턴스에 저장해서 그 인스턴스를 반환하도록 해야합니다.

일반적으로 immutable패턴을 read only object라고도 합니다. 예를 들면, 어떤 클래스(Foo)는 getter 메소드와 setter메소드를 모두 가집니다. 그리고 여러 일반 사용자에게 foo객체에 상태 정보를 변경하지 못하도록 제한하기 위해서 ReadOnlyIF를 만들 수 있습니다. ReadOnlyFooIF 인터페이스는 Foo클래스와 동일한 getter메소드들만 가집니다. 그래서 일반 사용자가 ReadOnlyIF를 통해서 간접적으로 Foo객체에 접근하게 함으로써 immutable 패턴의 robustness를 얻을 수 있게 되는 것입니다.

* 모든 인스턴스 변수는 불변해야합니다. 즉, 상수 혹은 "blank" 상수이어야 합니다. 그래야지만, 결국 공개(public)될수 있습니다.
* setter 즉 set 메소드가 없어야 하고 getter 즉 get 메소드만 있어야 합니다.
* 메소드에 의해 상태정보가 바뀐다면 새로운 인스턴스에 저장해서 그 인스턴스를 반환하도록 해야합니다.
* 이러한 이유들 때문에, Immutable 패턴은 멀티쓰레드의 사용을 유용하게 합니다. JAVA API USAGE Java API의 String클래스는 immutable 클래스의 대표적인 예입니다. String 클래스에서는 자신을 나타내는 연속적인 Character들은 객체가 생성될 때 정해지며 변하지 않습니다. String 클래스의 toLowerCase(), subString() 등의 메소드들은 자신의 상태정보(즉, 연속적인 Character들의 값)를 변경하지 않고 새로운 String 객체를 생성해서 반환합니다.



* 코드 예제

또 하나의 예로 2차원 공간의 위치를 나타내는 Position객체를 생각해 보겠습니다. Position에는 좌표의 위치를 나타내는 x와 y가 멤버변수로 존재합니다. 그리고 x와 y의 offset으로 새로운 Position객체를 생성하는 메소드를 가집니다. 이 메소드는 자신의 x값, y값을 변경하지 않고, 새로운 객체를 생성해서 반환하도록 합니다. Position클래스의 소스코드는 다음과 같습니다.



public class Position {
private int x;
private int y;

public Position(int x, int y) {
this.x = x;
this.y = y;
}
public int getX(){
return this.x;
}
public int getY() {
return this.y;
}
public Position offset(int xoffset, int yoffset) {
return new Position(x + xoffset, y + yoffset);
}
}
 



관련된 패턴 Single Threaded Execution(Concurrency Pattern)