달력

52025  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

CVS는 RCS를 기반으로 작성된 버전 관리 시스템입니다. 쉽게 얘기하자면 RCS는 파일 하나하나에 대해 버전 관리를 해주는 것이고, CVS는 RCS 기능을 이용해 소스나 문서를 프로젝트/모듈 단위로 관리할 수 있도록 확장한 프로그램입니다. 이미 RCS를 쓰고 있고 익숙한 분이 아니라면 굳이 CVS를 새로 배울 필요는 없습니다. RCS로 할 수 있는 모든 것은 CVS로 할 수 있지만 그 역은 성립하지 않기 때문입니다.


형상관리(Software Configuration Management)

 

형상 관리는 하드웨어에서 출발하였지만…소스는 변경될 때마다 새로운 버전이 생성되고, 추가되고, 삭제되고, 소프트웨어 개발 시에 발생하는 모든 작업은 시스템에 영향을 미치게 되므로 시스템에 영향을 주는 모든 사건을 버전화하고 소스를 버전별로 관리하는 일이 형상관리( 버전 관리란 용어를 사용하기도 합니다.)


Source control system (version control system) – locking system을 이용해 엑세스를 직렬화함으로써 소스코드 액세르를 제어하는 것과, 모든 파일의 변경사항 히스토리를 저장함으로써 이전 버전을 다시 불러와 구성할수 있게 하는 것


Pessimistic locking – 한번에 한사람만이 수정가능한 파일 사본을 가져올 수 있다, 수정 권한을 확보한 사람이 변경한 코드를 체크인해서 제어권을 넘겨주기 전까지는 어느 누구도 수정가능한 사본을 얻을 수 없으며, 읽기 전용 사본을 가져오는 것은 가능하다.


Optimistic locking사용자는 언제든 파일을 가져와 수정할 수 있다. 파일을 repository에 다시 체크인하면 버전 컨트롤 소프트웨어는 체크인하지 않은 다른 사람의 변경사항과 충돌이 일어나지 않도록 한다. 버전 컨트롤 시스템은 자동으로 변경사항을 병합할 수 있을 경우 병합하고 그렇지 않으면 직접 충돌을 해결해야 한다고 경고한다.


수정병합(Copy Modify Merge) - 소스를 복사하여 수정한 후에 병합이 가능한 구조로 동시에 하나의 파일을 가지고 작업하고 나중에 충돌되는 부분은 확인해가며 작업자간의 의견을 조율하여 소스에 반영하는 방식이다.(CVS, Subversion)


Lock Reservation – 작업을 하는 사용자가 잠금(lock)을 걸어놓고 작업하는 방식으로 잠금이 걸린 문서나 파일은 다른 사람의 열람은 가능하지만 수정하여 반영할 수는 없다. (Vusual SourceSafe, IBM Rational사의 ClearCase)


• Eclipse에 통합된 소스 컨트롤 툴 CVS(Concurrent Versions System)은 낙관적 잠금을 지원하며 수정병합 방식을 채택한 시스템이다.


CVS(Concurrent Versions System)는 오픈 소스 프로그램으로 WinCVS와 TortoiseCVS등의 클라이언트 프로그램이 존재하고, 이클립스, NetBeans, JBuilder, Idea(inteliJ)등의 개발 툴에 기본으로 통합되어 있다.


• CVS는 혼자하는 개발, 팀을 이루는 개발, 다국적 개발등에 유용하며 클라이언트 서버 구조로 잠금 상태를 예약하지 않는 수정병합 방식으로 같은 소스의 동시 작업이 가능하다


[CVS 기능]

• History 기능 – 소스파일이 추가되고, 수정되고 삭제되었던 모든 History가 CVS 서버에 기록되며 작업 완료 시에 작업 내용을 기록에 남길 수 있다.

• 변경사항 저장 – 파일의 모든 버전을 파일로 저장하는 대신 CVS는 버전간의 변경사항만을 저장하므로 백업 용량을 적게 차지한다.

• 병합 기능 – 각 개발자가 작업을 끝마쳤을 때, 그 작업을 병합시켜줌으로써, 팀원이 하나의 공동 프로젝트를 수행하고자 할 때 도움을 준다.

• branch 기능 – 개발의 주된 흐름인 메인 줄기(trunk)의 특정 진행 시점에서 갈라져 나와 개발을 추가하거나 변경된 가지(branch)에서 소스를 변경해도 메인 줄기에는 영향을 미치지 않는다.

• tag 기능 – 개발의 특정 시점에 버전을 따는 기능으로 개발이 빌드되거나 릴리즈되는 특정 시점에서 태그를 달고, 개발을 진행해 나간다.(특정 태그가 달린 소스를 찾아서 해당 태그의 모듈을 구할 수 있다)

• diff 기능 - 버전과 버전, 태그와 태그간에 소스의 차이점을 비교해준다.


[CVS 작업 사이클]

• 프로젝트 생성

프로젝트를 생성하고, 프로젝트 매니저나 리드 개발자가 CVS 서버에 프로젝트 저장소를 만든다.(init)

초기 버전에 대한 소스나 문서, 파일 등을 서버에 올린다.(CVS 서버에 모듈을 import)

• 프로젝트 진행

팀에 속한 모든 개발자는 import된 프로젝트 모듈을 다운로드하고(Checkout), 모듈의 소스를 추가(add), 삭제(remove), 커밋(commit), 변경(update) 중에 충돌(conflict)된 것은 합병(merge)하는 등 프로젝트를 진행한다.

일정시점이나 릴리즈 시에는 tag나 branch를 정해서 태그를 붙인다.


[CVS 내에서 사용되는 용어]

• repository – CVS를 통해서 작업하는 소스, 문서 등 작업용 파일이 저장되는 서버상의 공간

• revision – 각 파일별로 commit 할 때마다 자동으로 더해지는 버전으로 CVS가 관리하는 번호로 뒤로 돌리거나, 임의로 수정할 수 없다.

• init – 저장소를 초기화하는 명령어로 프로젝트를 시작할 때 한번만 실행

• module – 하나의 저장소에 구분되어 저장되는 단위.(작은 프로젝트의 경우 하나의 모듈, 큰 프로젝트의 경우에는 컴포넌트별로 모듈을 나누거나 버전별로 나누기도 함)

• import – 하나의 모듈을 서버에 저장하늠 명령어

• checkout – 서버에 저장한 모듈 하나를 통째로 로컬에 가져오는 명령어

• update – 파일이나 디렉토리를 지정하여 최신 것이나 특정 리비전, 특정 날짜의 것을 서버에서 로컬로 가져오는 명령어

• add – 새로운 파일을 디렉토리에 추가했음을 서버에 알리는 명령어.(파일은 commit하기 전까지는 서버에 반영되지 않는다.)

• remove – 파일 삭제했음을 서버에 알리는 명령어 (commit하기 전까지는 서버에서 지워지지 않는다.)

• commit – add, remove를 마치고 서버에 반영한다는 의미의 명령어

• tag – 특정 날짜나 릴리즈 시에 태그를 붙임으로써 나중에 해당 릴리즈의 리비전으로만 가져올 수 있게 한다.

• branch – 일부분 혹은 전체에서 소스를 별도로 관리해야 되는 부분이 생길 때 사용 (리비전의 깊이가 달라진다(예:1.1 > 1.1.2.1)
--------------------------------------------------------------------------------------------------------
CVS에서 유용하게 사용되는 변화 추적(Change-tracking)

CVS(Concurrent Versioning System)는 파일의 동시 개발을 관리한다. 파일을 중앙 저장소(repository)에 저장하고, 사용자는 파일 복사본을 받아서 작업하고 변경된 것을 다시 저장소로 보내기 때문이다.

CVS는 각 파일의 변경 기록을 관리하고, 사용자들이 이전 버전으로 복귀, 병합하거나 변경사항을 추적할 수 있게 해준다. 이 변화 추적(Change-tracking) 기능은 아주 유용하기 때문에 자주 사용될 것이다.

본 기사는 CVS 소개CVS 관리라는 두 기사를 바탕으로 작성되었다. 두 기사에서 이미 논의한 바 있는 특정 내용에 대한 언급이 있겠지만 이 기사에서 다시 자세히 설명하는 것은 생략하기로 하겠다.

annotate

anontate는 저장소에 저장된 파일의 각 라인에서 가장 마지막으로 변경된 내용을 보여주는 cvs 명령어이다. 각각의 라인에 대해 이 명령어는 라인의 내용, 날짜, 사용자, 가장 마지막으로 변경된 라인에 대한 변경 번호를 보여준다. 따라서 언제, 누가, 무엇을 변경했는지 알 수 있는 빠른 방법이라고 할 수 있다.

annotate는 현재 작업 중인 디렉토리에서가 아니라 저장소에서 파일 데이터를 출력하므로, 아직 커밋(commit)되지 않은 변경 내용은 보이지 않는다.

cvs annotate의 옵션은 다음과 같다.

-f

일치하는 태그나 데이터가 그 파일에서 발견되지 않는다고 하더라도 (최신 변경 정보를 사용하여) 파일을 보여준다.

-l

현재 디렉토리만 확인하고 하위 디렉토리는 확인하지 않는다.

-R

하위 디렉토리를 확인한다(기본값).

-D date

지정된 날짜를 기준으로 가장 최근에 변경된 내용을 보여준다.

-r tag

태그(꼬리표)로 구분할 수 있는 변경된 내용을 출력한다.

Example 1

$ cvs annotate test.html
Annotations for test.html
***************
1.1 (jenn 30-Apr-02): <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
1.1 (jenn 30-Apr-02): "http://www.w3.org/TR/html4/strict.dtd">
1.1 (jenn 30-Apr-02): <html>
1.1 (jenn 30-Apr-02): <head>
1.4 (jenn 04-May-02): <title>Sample Article</title>
1.1 (jenn 30-Apr-02): </head>
1.1 (jenn 30-Apr-02): <body>
1.4 (jenn 04-May-02): <h1>Sample Article</h1>
1.1 (jenn 30-Apr-02): <p>
1.11 (jenn 07-May-02): Body text for the sample article.
1.1 (jenn 30-Apr-02): </p>

CVS Pocket Reference

참고 도서

CVS Pocket Reference
Gregor N. Purdy


diff

cvs diff는 한 파일의 두 가지의 다른 변경된 내용을 비교하여 차이점을 보여주는 명령어이다. cvs diff의 출력된 내용(output)은 표준 diff 명령어의 출력 내용과 매우 유사하다. cvs rdiff는 표준 patch 명령어를 사용하여 설치될 수 있는 패치 파일을 만드는데 사용된다.

대개 cvs diff는 적어도 하나 이상의 -r tag 파라미터(parameter)와 함께 사용된다. 만약 단일 태그와 함께 호출된다면 작업중인 디렉토리에 있는 현재 복사본은 저장소에 있는 버전과 비교된다. cvs log 명령어는 cvs diff의 파라미터로 사용될 수 있는 변경 번호를 보여준다.

Example 2

$ cvs diff -r 1.11 cvs_changes.html
Index: cvs_changes.html
===================================================================
RCS file: /home/cvs/oreilly/articles/cvs/cvs_changes.html,v
retrieving revision 1.11
diff -r1.11 cvs_changes.html
64a65
&gt; The command &lt;code&gt;cvs diff&lt;/code&gt; compares two 
revisions of a file and displays the differences.
66a68
&gt; &lt;code&gt;cvs diff&lt;/code&gt; is usually called with at 
least one &lt;code&gt;-r &lt;var&gt;tag&lt;/var&gt;&lt;/code&gt; parameter.
71a74

history

대부분의 CVS 기능과는 달리,
cvs history 는 디폴트로 셋업되지 않는다. 셋업하려면 저장소의 CVSROOT 디렉토리 안에 history 라는 파일을 생성해야 한다. CVS 사용자는 (또는 서버에서 CVS를 실행할 수 있는 사용자는 모두) 그 파일을 작성할 수 있어야 한다.

Example 3

(on the cvs repository server)
$ cd /home/cvs/CVSROOT
$ touch history
$ chmod g+w history
$ ls -la
drwxrwsr-x    4 root     src          1024 May 16 01:04 .
drwxrwsr-x   35 root     src          1024 Mar 20 18:01 ..
drwxrwsr-x    2 root     src          1024 Sep  7  2001 Attic
-rw-rw-r--    1 root     src             0 May 16 01:04 history
-r--r--r--    1 root     src           403 Sep 26  2001 loginfo

파일을 커밋하고 cvs history -c filename 실행해서 history 파일을 테스트하자(-c 플래그는 CVS 커밋을 표시함). CVS는 history 파일이 생성된 후로 하나의 커밋된 내용을 보여주는 라인을 하나 표시할 것이다.

Example 4

$ cvs history -c test.html
M 2002-05-15 15:04 +0000 jenn 1.2 test.html oreilly/articles/cvs ==  $ 

일단 셋업되면 cvs history는 저장소에 있는 파일과 모듈의 히스토리를 보여주는데 사용될 수 있다. 파일과 모듈 선택은 현재 작업 디렉토리 내에 있는 모듈들, 모듈, 특정 파일이나 파일들을 포함한다.

history 파일은 저장소 안에 저장된 파일의 커밋, 병합, 충돌, 태그(꼬리표), (작업 디렉토리에)업데이트, 추가, 삭제, 변경 등을 기록한다. 이들 각각은
cvs history 명령어로 소환되거나 표시될 수 있다.

cvs history는 사용자 요구 정보, 모든 사용자 또는 현재 작업 중인 복사본의 데이터를 표시할 것이다. 넓게 분포되어 작업하는 팀들을 위해 지정된 시간대에 맞게 시간을 표시하는 옵션을 가지고 있다.

Example 5

$ cvs history -e -w -z EST test.html
M 2002-05-15 10:04 EST jenn 1.2 test.html oreilly/articles/cvs == <remote>
M 2002-05-15 10:41 EST jenn 1.3 test.html oreilly/articles/cvs == <remote>

예제5에서 -e 는 커밋과 업데이트의 모든 타입를 표시하도록 하고, -w 는 현재 작업중인 디렉토리에서 유래하거나 영향을 받은 변경 내용만 표시하도록 한다. 그리고 -z EST는 동부 표준시간대(EST)로 표시하도록 하기 위해 시간대를 설정한다.

log

cvs log 명령어는 인자로 전달되는 파일(들)에 대한 정보를 표시한다. 만약 파일이 전달되지 않는다면 현재 작업 디렉토리와 그 하위 디렉토리의 모든 파일들에 대한 로그 정보를 표시한다.

cvs log를 위한 옵션은 보여주는 정보의 양을 줄인다. 디폴트로 log는 가지고 있는 모든 정보를 보여준다.

Example 6

$ cvs log cvs_changes.html

RCS file: /home/cvs/oreilly/articles/cvs/cvs_changes.html,v
Working file: cvs_changes.html
head: 1.3
branch:
locks: strict
access list:
symbolic names:
keyword substitution: kv
total revisions: 3;     selected revisions: 3
description:
----------------------------
revision 1.3
date: 2002/05/15 15:41:54;  author: jenn;  state: Exp;  lines: +53 -0
history mostly done. needs example.
----------------------------
revision 1.2
date: 2002/05/15 15:04:47;  author: jenn;  state: Exp;  lines: +8 -2
Adding a history file
----------------------------
revision 1.1
date: 2002/05/15 14:54:54;  author: jenn;  state: Exp;
Initial entry for both files. Also includes cvs annotate for changes.
====================================================================

예제6은 본 기사에 대한 초기 로그 히스토리를 보여준다.

Revision 1.1은 내가 두 개의 파일을 만들고 그 빈 템플릿을 체크인(check-in)하는 것을 잊어버리고 본 기사의 주석 부분을 커밋하기 위해 노력할 때 발생하였다.

사용자 정의 로깅

CVS는 확실하다고 생각하는 행동이 일어났을 때 호출되는 스크립트를 정의하는 커스터마이즈된 파일들을 가지고 있다.
loginfo(로그정보), 모듈들과 taginfo(태그정보) 파일은 로깅 스크립트들을 호출하기 위해 사용될 수 있다.

이런 파일들은 CVS 저장소의 CVSROOT 디렉토리에서 찾을 수 있고, 그곳에서 형성된다. 그 파일들은 호스트 컴퓨터에서 실행하지만 몇몇 모듈 스크립트들은 클라이언트 머신에서 실행된다. 더 자세한 내용은 다음을 참고하기 바란다.

CVSROOT 모듈 내에 있는 파일들을 편집할 때에는 CVS를 이용하라. 모든 파일을 체크아웃(† 역자 주: checkout, 가져오다)하기 위해서는 단순히
cvs -d repository checkout CVSROOT만 실행하면 된다.

loginfo와 taginfo

loginfo 파일은 cvs commit을 위한 로그 정보를 어디로 보내야 할지를 통제한다. 프로젝트 리더가 팀이 만든 변경된 내용을 유지하고 프로젝트의 진행상의 주요한 로그를 유지하는데 사용할 수 있다.

taginfotagrtag 명령어를 위한 것이지만 loginfo도 마찬가지로 사용된다. taginfologinfo와 같은 문법을 가지고 있다.

파일의 각 라인은 디렉토리에 적합한 정규 표현식을 포함해야 한다. 이 디렉토리는 스크립트 주소순으로 표준입력(stdin)과 같은 로그 정보를 예상한다.

특수한 라인들은 'ALL'과 'DEFAULT'로 시작한다. ALL은 적용되는 다른 라인들을 누적하여 실행한다. 만약 그렇지 않으면 처음으로 짝지워진 정규 표현식만 실행되고 나머지 짝지워지지 않은 것들은 DEFAULT로 된다.

예제7의
loginfo 파일은 logscript 스크립트를 통해 커밋되는 모든 것을 로그로 남길 것이다. 그리고 $CVSROOT/oreilly 디렉토리 내의 어떠한 파일이 커밋될 않을 경우, cvsscript를 실행하고 cvsadmin으로 다른 커밋을 메일로 보낼 것이다.

Example 7

ALL /usr/local/bin/logscript
^oreilly /home/jenn/scripts/cvsscript
DEFAULT Mail -s "CVS commit" cvsadmin

modules

CVSROOT/modules 파일은 각각의 모듈과 이들의 디렉토리, 파일들을 기록한다. 그 파일(CVSROOT/modules)은 또한 옵션들을 사용한다. 몇몇 옵션들은 CVS 동작이 발생할 때 실행되는 스크립트들이다.

-e script

모듈이 익스포트(export)되었을 때 script를 실행한다.

-i script

모듈이 커밋 되었을 때 실행한다.

-o script

모듈이 체크아웃 되었을 때 실행한다.

-u script

모듈이 업데이트(갱신) 되었을 때 실행한다.

-t script

rtag가 모듈에 사용되었을 때 실행한다. 이것은 tag가 사용되었을 때는 실행되지 않는다. taginfo 파일이 태그의 로그를 남기는 더 좋은 방법이다.



만약 이 파일(CVSROOT/modules)을 변경하고 싶다면 CVS 매뉴얼과 정보 파일을 읽어보기 바란다. CVS는 사용자가 모듈과 상호작용을 할 때 항상 이 파일을 사용한다.

커밋이나 업데이트를 할 때 호출되는 스크립트들은 로컬 머신에서 실행되고, 나머지 스크립트들은 서버에서 실행된다.

예제8은 oreilly 모듈이 oreilly 디렉토리에서 체크아웃될 때 /home/jenn/scripts/cvsscript를 실행하려 한다. 이것 또한 특별한 옵션 없이 CVSROOT 모듈을 정의한다.

Example 8

CVSROOT CVSROOT
oreilly -o /home/jenn/scripts/cvsscript oreilly

마지막으로

Change-tracking(변화 추적)은 CVS의 유용한 부분임에도 불구하고 현장에서 사용하는 것을 거의 보지 못했다. 처음으로 CVS를 사용하기 시작했을 때 변화 추적의 특징을 발견하고 순간 "내가 왜 전에는 이것을 사용하지 않았을까?"라고 생각하였다.

여러분도 한 번씩 해보기 바란다. 그리고 내가 그랬던 것처럼 이것의 유용한 점을 발견하길 바란다.

'SVN/CVS' 카테고리의 다른 글

버전관리 시스템(#1 SVN 바로알기)  (0) 2010.01.04
SVN(Subversion)  (0) 2010.01.04
CVS-개념 및 리눅스 서버 설치  (0) 2010.01.04
Posted by 인천총각
|

■ 기본 커맨드 패턴

1. 커맨드 객체는 특정 객체에 대한 특정 작업 요청을 함께 캡슐화한다.


[그림] 커맨드 객체 구조

실제로, 요청을 처리하는 리시버(receiver)에 대한 참조와 Execute() 메소드를 가지고 있다. Execute()에서는 리시버의 메소드를 호출함으로써 필요에 따라서는 일련의 메소드를 복수해 호출해서 비즈니스 요청을 수행한다. 커맨드 객체를 호출하는 측에서는 단지 Execute() 메소드만 호출하면 된다. 그 커맨드가 구체적으로 Execute()를 어떻게 구현하는지는 알 필요가 없다.

2. 작업을 요청하는 쪽(리모콘)과 작업을 하는 쪽(TV, CD 플레이어)을 커맨드 객체를 통해서 분리할 수 있다.

3. 캡슐화시 매개변수를 써서 여러 가지 다른 요구사항을 집어넣을 수도 있다.

ConcreteCommand(매개변수);

4. 커맨드 패턴을 사용하면 요청 내역을 큐에 저장해서 스케쥴러, 작업큐같은 프로그램을 만들거나 또는 작업 내역을 스택성 로그로 기록해서 도중에 에러가 발생하면 롤백하는 구조의 프로그램을 만들 수도 있다. 이것을 좀더 정교하게 만들면 트랜잭션 시스템을 구현하는 것도 가능하다.

레퍼런스

Head First Design Patterns 스토리가 있는 패턴 학습법

-Oreilly, 한빛 미디어

■ 커맨드 패턴 변형

앞에서는 커맨드 객체가 리시버(Receiver)에 대한 참조와 그 리시버를 이용해서 요청을 구현해야 하는 Execute()가 있어야 한다. 이런 경우는 리시버에 대한 참조를 가지고 있어야 한다는 점에서 리시버와 커맨드 객체와의 커플링이 존재하게 된다. 이런 커플링을 없애기 위해서 때로는 리시버와 Execute() 대신에 단일 이벤트 멤버로 대신할 수 있다.


[그림] 커맨드 객체

1. One handler : 하나의 이벤트 핸들러에서 여러 UI 이벤트(메뉴, 툴바)를 핸들링할 수 있다.

2. the business logic for handling the command : 그 하나의 이벤트 핸들러에 해당 명령을 핸들링할 수 있는 비즈니스 로직을 중앙 관리할 수 있다.

■ 커맨드 패턴 구현의 핵심 요소

커맨드 관리자

- 애플리케이션에서 필요로 하는 모든 커맨드들의 중앙 저장소

- 애플리케이션이 커맨드 목록을 관리할 수 있는 컬렉션용 API를 제공.

레퍼런스

Command Management
--------------------------------------------------------------------------------------------------------

Command Pattern

메소드 호출을 캡슐화 하는 패턴이다. 메소드 호출을 캡슐화하면 계산 과정의 각 부분들을 결정화 시킬 수 있기 때문에 계산하는 코드를 호출한 객체에서는 어떤 식으로 일을 처리해야 하는 지에 대해서 전혀 신경 쓰지 않아도 된다.

 

 

1.     Command Pattern의 정의

커맨드 패턴을 이용하면 요구 사항을 객체로 캡슐화 할 수 있으며, 매개변수를 써서 여러 가지 다른 요구 사항을 집어넣을 수도 있다. 또한 요청한 내역을 큐에 저장하거나 로그로 기록할 수도 있으며, 작업 취소 기능도 지원 가능하다,

 

2.     Command Pattern의 특성

커맨드 패턴을 사용하면 어떤 작업을 요청한 쪽하고 그 작업을 처리한 쪽을 분리시킬 수 있다. 커맨드 객체는 특정 객체에 대한 특정 작업 요청을 캡슐화한다. 커맨드 객체는 일련의 행동을 특정 리시버하고 연결시킴으로써 요구 사항을 캡슐화한 것이다. 행동과 리시버를 한 rorrorc 집어넣고, excute()라는 메소드 하나만 외부에 공개하여 이 메소드 호출에 의해서 리시버에서 일련의 작업이 처리된다. 외부에서 볼 때는 어떤 객체가 리시버 역할을 하는지, 그 리시버로 실제로 어떤 일을 하는지 알 수 없다. Excute()메소드를 호출하면 요구 사항이 처리된다는 것만 알 수 있을 뿐이다. 커맨드를 확장해서 여러 개의 커맨드를 한꺼번에 호출할 수 있게 해주는 매크로 커맨드 패턴도 있다.

 

3.     Command Pattern의 클래스 다이어그램



 

4.     Command Pattern의 구성

A.     클라이언트는 ConcreteCommand를 생성하고 Receiver를 설정한다.

B.     Invoker에는 명령이 들어있으며, execute()메소드를 호출함으로써 커맨드 객체에게 특정 작업을 수행해 달라는 요청을 하게 된다.

C.     Command는 모든 커맨드 객체에서 구현해야 하는 인터페이스 이다. 모든 명령은 execute()메소드 호출을 통해서 수행되며, 이 메소드에서는 리시버에 특정 작업을 처리하라는 지시를 전달한다.

D.     Execute() 메소드에서는 리시버에 있는 메소드를 호출하여 요청된 작업을 수행한다.

E.      Receiver는 요구사항을 수행하기 위해 어떤 일을 처리해야 하는지 알고 있는 객체이다.

F.      ConcreteCommand는 특정행동과 리시버 사이를 연결 해준다.

 

5.     Command Pattern의 장단점

커맨드 패턴은 작업을 요청하는 객체와 실제 작업을 수행하는 객체를 분리시켜주므로 시스템의 결합도가 낮아질 수 있으며, 두 객체가 독립적으로 변경 가능한 장점을 가진다. 커맨드 및 그 하위 클래스는 기존 클래스와 무관하게 확장이 가능하며, 확장된 클래스들은 클라이언트의 별다른 수정 없이 사용이 가능하다. Macro Command처럼 커맨드패턴에 컴포지트 패턴을 복합해서 적용할 경우 복잡한 작업을 기본적인 작업들로 구조화시켜 다룰 수 있는 장점이 있다
----------------------------------------------------------------------------------------------------

커맨드패턴
 
메소드의 호출을 캡슐화 한다는 것이 핵심입니다.
메소드 호출을 캡슐화하면 계산과정의 각 부분들을 결정화시킬수 있기 때문에 계산하는 코드를 호출한 객체에서는 어떤식으로 처리해야하는지에 대해 전혀 신경 쓰지 않아도 됩니다.
 
* 클라이언트는 ConcreateCommand를 생성하고 Receiver 를 설정합니다.
* Invoker 에는 명령이 들어 있으며 , execute() 메소드를 호출함으로써 커맨드 객체에게 특정 잡업을 수행해 달라는 요구
  를 하게 됩니다.
* Command 는 커맨드 객체에서 구현해야하는 인터페이스입니다.
* Receiver 는 요구사항을 수행하기 위해 어떤일을 처리해야 하는지 알고 있는 객체입니다.
* ConcreteCommand 는 특정행동과 리시버 사이를 연결해 줍니다. 인보커에서 execute() 호출을 통해 요청하면
  ConcreteCommand객체에서 리시버에 있는 메소드를 호출함으로써 그 작업을 처리합니다.
 
 
예제를 보면서 설명하겠습니다..
다음 코드는 전등을 켜는 리모콘을 생성하여 처리하는 과정을 보여줍니다.
 
우선은 커맨트 인터페이스를 생성합니다. 당연히 execute()메소드를 정의합니다.

 Command.java
 

public interface Command {
 public void execute();
}

 

 실제 작업을 정의한 Receiver 객체입니다. 

 Light.java
 

public class Light {
 
 public void on()
 {
  System.out.println("불 켜다");
 }
 public void off()
 {
  System.out.println("불 끄다");
 }

}

 

 실제작업을 실행할 커맨드 클래스 ConcreteCommand 를 구현한다. 

 LightOnCommand.java
 

public class LightOnCommand implements Command {
 
 Light light;
 
 public LightOnCommand(Light light)
 {
  this.light = light;

 // 생성자에서 이 커맨드 객체를 제어할 특정 정보를 전달합니다..그 객체는 light라는 인스턴스 변수에 저장되고

 // execute() 메소드가 호출되면 light 객체가 바로 그 요청에 대한 리시버가 됩니다.
 }

 public void execute() {
  light.on();
 }

}

 

버튼이 하나 밖에 없는 리모콘을 만들어 보면. 다음과 같다.

 SimpleRemoteControl.java
 

public class SimpleRemoteControl {
 Command slot;
  // 커맨드를 집어넣을 슬롯이 하나 밖에 없습니다. 이걸가지고 장비를 제어합니다.
 public SimpleRemoteControl() {}
 

 

// 슬롯을 가지고 제어할 명령을 설정하기 위한 메소드
 public void setCommand(Command command)
 {
  slot = command;
 }
 
 public void buttonWasPressed()
 {
  slot.execute();
 }
}

 

자 이제 테스트클래스를 만들고 실행해보자.

 RemoteControlTest.java
 

public class RemoteControlTest {

 public static void main(String[] args) {
  
  SimpleRemoteControl remote = new SimpleRemoteControl();

//remote 변수가 인보커(invoker)역할을 합니다.

//필요한 작업을 요청할 때 사용할 커맨드 객체를 인자로 전달 받는다.


  Light light = new Light();

//리시버 객체를 생성


  LightOnCommand lightOn = new LightOnCommand(light);

//커맨드 객체를 생성합니다. 이때 리시버를 전달합니다.
  
  remote.setCommand(lightOn);

//커맨드 객체를 인보커한테 전달합니다.
  remote.buttonWasPressed();


 }

}

 

 

커맨드 객체는 일련의 행동을 특정 리시버하고 연결시킴으로써 요구사항을 캡슐화한다.

이렇게 하기 위해서 행동과 리시버를 한 객체에 집어 넣고, execute() 라는 메소드 하나만 외부에 공개하는 방법을 사용한다. 메소드 호출에 의해서 리시버에서 일련의 작업이 처리된다. 외부에서 볼때는 어떤 객체가 리시버 역할을 하는지 그 리시버에서 실제로 어떤 일을 하는지 알 수 없습니다. 다만 execute()메소드를 호출하면 요구사항이 처리 된다는 것만 알수 있다.

 

정리하자면

커맨드 패턴을 사용하면 요청하는 객체와 그 요청을 분리시킬수 있다.

이렇게 분리시키는 과정의 중심에는 커맨드객체가 있으며 이객체가 행동이 들어있는 리시버를 캡슐화 한다.

인보커에서는 요청을 할때는 커맨드 객체의 execute()메소드만 호출하면 된다.

execute() 메소드에서는 리시버에 있는 행동을 호출한다.

 

적용예

스트러츠1.0 에서 Action클래스의 execute 메소드가 있다.

 

정의

요청내역을 객체로 캡슐화하여 클라이언트를 서로 다른 요청에 따라 매개변수화 할 수 있습니다.

Posted by 인천총각
|

APPLET 이란???

Applet 2009. 12. 29. 13:07

APPLET 이란 ?

▷ Applet은 HTML 페이지에 내장되어 Web Browser의해 download되고 수행된다.
    Applet의 수행은 application의 수행과 분명히 구분된다.
    Application은 main()문 부터 수행이 되지만, applet은 수행의 시작을 비롯한 life cycle이 좀 더 복잡하다.

Applet Security Restrictions(애플릿의 보안)

▷ applet은 다른 곳에 떨어져 있는 사이트에서 load되어 local에서 실행되도록 설계되었기 때문에 보안이 중요하다.
   만약 내 컴퓨터에 중요한 정보가 있었다면 그것을 몰래 가져갈 수도 있을 것이다. 

▷ Web browser Security Manager는 applet이 접근 규칙을 위반할 경우 SecurityException이 발생한다.

▷ 대부분의 applet에 적용되는 보안은 browser 수준에서 이루어지는데, 아래와 같은 작업을 제한하고 있다.

  -Local system상의 다른 프로그램의 수행.
  -File I/O
  -Native method 호출
  -Applet이 다운로드된 host이외의 host에 대한 소켓(socket)연결

JDK1.2에서는 URL단위로 보안을 설정할 수 있고, 보안 정책을 따로 둘 수가 있다.

Writing an Applet
Applet은 다음과 같은 형식으로 class가 만들어진다.

예)     import java.applet.*;
        public class HelloWorld extends Applet {

Applet은 반드시 public class로 되어야 하며, file의 이름이 class의 이름과 같아야 한다.
(html 파일이름은 달라도 된다.)

Applet Class Hierarchy
Applet class는 Panel class의 subclass이다. 때문에 applet은 flowlayout을 기본 layout으로 한다.

java.lang.Object

|

+--java.awt.Component

|

+--java.awt.Container

|

+--java.awt.Panel

|

+--java.applet.Applet

주요 Applet Methods

public class Simple extends java.applet.Applet {

. . .

public void init()

{ . . . }/* 애플릿이 로드되거나 재로드될 때 처음으로 수행되는 코드 */

public void start()

{ . . . }/* 애플릿이 로드되거나 사용자가 재방문했을 때 수행되는 코드 */

public void stop()

{ . . . }/* 애플릿이 있는 페이지를 떠나거나 브라우저를 중지했을 때 수행되는 코드 */

public void destroy()

{ . . . }/* 로드를 취소하였을 때(cleanup) 수행되는 코드 */

}

▷ init() - 한번만 호출된다. 애플릿이 처음 생성되고 브라우저에 load될 때 호출되는 메소드이다. 이 메소드는 애플릿에 필요한 초기화를 제공한다. 이 메소드는 생성자와 비슷하게 동작하여 자바가 애플릿을 처음 로드할때에 자동적으로 시스템에 의해 호출된다. 보통 PARAM 값을 처리하고 사용자 인터페이스를 추가한다.

▷ start() - init() 이후에 애플릿이 동작하기 시작할 때 구동되는 메소드이다. init() 메소드가 호출된 후에 자동적으로 호출된다. 그리고 사용자가 다른 페이지로부터 이 애플릿을 포함한 페이지로다시 돌아올 때마다 호출된다. 이것은 start 메소드가 init 메소드와는 달리 반복적으로 호출된다는 것을 의미한다. 그러므로 단 한번만 실행되어야 할 코드는 init 메소드에 넣어야 한다.

▷ stop() - 애플릿이 동작을 멈출 때 구동된다. 다른 URL로 접속된 경우에 호출된다. 즉, 이 메소드는 사용자가 애플릿이 있는 현재의 페이지를 나오면 자동적으로 실행된다. 그러므로, 동일한 애플릿에 대해 반복적으로 호출된다. 그 목적은 사용자가 애플릿에 관심을 두지 않을 때 시스템 속도를 저하시키는 시간 소모적인 활동을 하지 않도록 하는 기회를 제공하는 것이다.

▷ destroy() - 브라우저가 정상적으로 종료될 때에 이 메소드를 호출하도록 되어 있다. 애플릿은 HTML 파일 내부에 있도록 되어 있으므로, 이 메소드는 브라우저가 종료될때에 자동적으로 일어난다. destroy 메소드에 집어넣어야 할 것은 사용자가 소비한 윈도우 핸들러와 같은 비 메모리 의존 자원을 회수하는 코드이다. 물론, 만일 애플릿이 여전히 활동하고 있다면, 자바는 destroy 메소드를 호출하기 전에 stop 메소드를 호출한다.

Applet Display

▷ Applet은 그래픽하게 나타난다. System.out.println()은 사용할 수 없다. 대신 paint() method를 사용하여 applet's panel에 원하는 것을 그릴 수 있다. paint() method는 browser에 의해서 applet의 display가 새로고쳐질 필요가 있을 때마다 호출되어야 한다.(repaint())

Applet Painting

▷ Applet에서 painting을 하기위해서 호출되어지는 method이다. 그리고, 아래와 같은 Cycle에서 의해서 applet이 보여진다.

▶ paint(Graphics g)

▶ repaint()

▶ update(Graphics g)

Applet Attribute

▷ Appelt attribute의 예

<applet

[archive=archiveList]

code = appletfile.class

width=pixels height=pixels

[codebase=codebaseURL]

[alt=alternateText]

[name=appletInstanceName]

[align=alignment]

[vspace=pixels]

[hspace=pixels] >

[<param name =appletAttribute1 value=value>]

[<param name =appletAttribute2 value=value>]

[alternateHTML]

</applet>

▷ 위치에 관련된 applet attribute

▶ width , height - 이 속성은 반드시 해야 하며, applet의 폭과 높이를 픽셀 단위로 준다. appletviewer의 경우, 이것은 applet의 초기크기이다.

▶ align - 이 속성은 applet의 정렬방식을 지정한다. 기본적으로 두가지가 있다.

애플릿이 블록(block)인 경우 텍스트는 applet 주위에, 애플릿이 인라인(inline)인 경우에는 확대된 텍스트 문자인 것처럼 보이게된다.

▷ 코딩을 위한 applet attribute

▶ CODE - 이 태그에는 클래스 파일의 이름을 쓴다. 이 이름은 현재 HTML이 있는 곳으로부터 상대적인 값으로 취해진다.
                  이것은 local 디렉토리이거나 네트웍 URL이 될 수 있고 절대 경로 이름도 사용될 수 있다. 즉 C:/a.html

▶ CODEBASE - 이 속성은 선택적으로 사용할 수 있다. 현재 HTML문서가 위치한 디렉토리의 아래의 CODEBASE의 tag값에서 클래스 파일을 찾을 수 있음을 브라우저에 알린다. 예를 들어 아래의 코드는 MyWork/java/samples/HelloWorld.class의 바이트 코드를 읽어온다.

<applet code=HelloWorld codebase=MyWork/java/samples width=100 height=100>

▶ Archive

- 자바 1.1에서는 여러 파일을 압축하여 한번에 다운로드할 수 있도록 jar(Java ARchive)를 지원하는데 브라우저가 서버로부터 다운로드해야 할 jar 파일이 있을 때 사용한다.

archive = "mysamples.jar, morefiles.jar"

- JAR를 사용하면 파일(바이트코드)의 다운로드 속도를 상당히 개선할 수 있으며 파일의 관리도 매우 편리하게 된다. 이러한 기술은 HTTP의 요구가 많은 소용량의 파일을 포함하는 JAR 파일을 로드함이 필요함에도 불구하고 로드 프로세서의 속도를 현저하게 증가시킨다.
(100개의 파일인 경우 100번 연결을 줄일수 있다)

- Swing.jar or SwingAll.jar 파일은 1Mbyte 정도로 다운로드하기 힘들지만, 한번만 다운을 받으면 된다.

▷ PARAM 태그 - HTML 페이지로부터 애플릿에게 파라미터를 전달하는데 사용된다.

<param name=X value=ABC>

▶ value의 값은 String이어야 한다.

▶ 파라미터 값을 읽을 때에는 getParameter() 메소드를 사용한다.

String getParameter(String a)

▶ 위에서 name은 대소문자를 구분하지 않으나 (즉 섞어서 사용해도 되나) getParameter()이 리턴한 String 값은 대소문자를 구분하며 param 태그의 value에 지정된 값이 그대로 나타난다.

▶ 참고로 String 값은 해당 정수로 바꾸려면 parseInt()를 사용한다. 예를들어 파라미터 name이 AGE인 경우 이를 받아 정수값으로 변환하려면 다음과 같이 한다.

int age = 0;

age = Interger.parseInt(getParameter("AGE"));

▶ getParameter() 호출시 해당 파라미터가 HTML 페이지 내에 없으면 null-pointer exception이 발생한다.

▶ 주의: <param> 태그는 반드시 <applet>와 </applet> 사이에 와야 한다.

Applet에서의 추가 메쏘드

▷ 자바에서 애플릿 프로그램을 작성하기 위해서는 반드시 Applet 클래스로부터 계승된 클래스를 사용하여야 하는데 Applet 클래스는 java.applet 패키지에 속해 있다. Applet클래스의 주요 메소드는 다음과 같다.

URL getCodeBase();/* 코드 URL을 얻는다 */

URL getDocumentBase();/* 도큐멘트 URL을 얻는다 */

Image getImage(URL);/* URL로부터 이미지를 얻는다 */

Image getImage(URL, String); /* URL로부터 name에 해당하는 이미지를 얻는다 */

void play(URL);/* 해당 URL의 오디오 파일을 연주한다 */

void showDocument(URL);/* URL의 도큐멘트를 보여준다 */

getDocumentBase() - 현재 나타나고 있는 페이지의 HTML 문서가 있는 디렉토리를 URL 타입으로 리턴한다.

getCodeBase() - 애플릿 코드를 가져온 곳의 디렉토리를 URL 타입으로 리턴한다.

getImage(URL base, String target) - URL 위치에 있는 target이름의 image를 가져 온다.

getAudioClip(URL base, String target) - URL 위치에 있는 target 이름의 AudioClip을 가져온다.

Posted by 인천총각
|