eclipse 셋팅 기존의 ADT번들 배포판은 사라지고

eclipse에 ADT 를 설치 할수 있는 가이드만 제공 하고 있음.

 

안드로이드 개발 사이트 내에 Eclipse with ADT

http://developer.android.com/sdk/installing/installing-adt.html

 

이클립스에서 HELP->Install New Software

https://dl-ssl.google.com/android/eclipse/

 

이후 필요에 따른 안드로이드 버전별 SDK 설치

 

Posted by brent.lee


-- 무조건 올림
SELECT CEIL(13.11) FROM DUAL;

   

-- 반올림
SELECT ROUND(345.123, 0), ROUND(345.123,2), ROUND(345.123, -1) FROM DUAL;

   

-- 나머지
SELECT MOD(23,5) FROM DUAL;

   

-- 승수값
SELECT POWER(3,2), POWER(3, -2) FROM DUAL;

   

-- 버림값
SELECT TRUNC(345.123, 1), TRUNC(345.123, 0), TRUNC(345.123, -1) FROM DUAL;

   

-- 양수이면 1, 0이면 0, 음수이면 -1

SELECT SIGN(5.342), SIGN(0), SIGN(-2334) FROM DUAL;

   

   

-- IF + THEN 1 ELSIF - THEN -1 ELSE 0
SELECT DECODE( SIGN(POWER(2,10)-1000), 1, '2의 10승이 1000보다 크다',
-1, '2의 10승이 1000보다 작다', '2의 10승이 1000이다') 비교답 FROM DUAL;

   

-- ASCII <--> CHAR
SELECT CHR(65) "CHR", ASCII('A') "ASCII" FROM DUAL;

   

-- 대소문자 변환
SELECT LOWER('My name is KIMJINDOO') "LOWER", UPPER('My name is kimjindoo') "UPPER" FROM DUAL;

   

-- 자릿수 맞춰 채우기
SELECT LPAD('DALMA', 10, '*') "LPAD", RPAD('DALMA', LENGTH('DALMA')+11, '@dalcom.net') "RPAD" FROM DUAL;
SELECT LPAD('1234567890', 20, '+') || RPAD('1234567890', 20, '^') "1234567890" FROM DUAL;
SELECT LPAD('1,234,567', 30, ' ') "LPAD 사용으로 30자리 맞춤", '1,234,567' "단순문자 사용",
1234567 "단순숫자 사용" FROM DUAL;

   

-- 공백 제거
SELECT REPLACE(LTRIM('    AAA    '), ' ', '0') "LTRIM",
REPLACE(RTRIM('    AAA    '), ' ', '0') "RTRIM" FROM DUAL;

   

-- 문자열 치환
SELECT REPLACE('ORACLE', 'A', 'a') "REPLACE" FROM DUAL;
SELECT EMP_NAME, REPLACE(EMP_NAME, '이', '박') "이->박" FROM PERSONNEL WHERE EMP_NAME LIKE '이%';

   

-- 문자열의 일부만을 취하기
SELECT SUBSTR('ORACLE 프로젝트', 1, 3) SUBSTR1, SUBSTR('오라클 프로젝트', 4, 5) SUBSTR2,
SUBSTR('오라클 PROJECT', 10) SUBSTR3 FROM DUAL;
SELECT SUBSTRB('ORACLE 프로젝트', 2, 3) SUBSTRB1, SUBSTRB('오라클 프로젝트', 4, 5) SUBSTRB2,
SUBSTRB('오라클 PROJECT', 10) SUBSTRB3 FROM DUAL;


-- 문자열의 길이
SELECT EMPNO, LENGTH(EMPNO), LENGTHB(EMPNO), EMP_NAME, LENGTH(EMP_NAME), LENGTHB(EMP_NAME) FROM
PERSONNEL WHERE EMPNO>'98102'
SELECT LENGTH('가나다') "LENGTH", LENGTHB('가나다') "LENGTHB" FROM DUAL;

-- LANGUAGE : KOREAN_KOREA.KO16KSC5601
SELECT LENGTH('학교') FROM DUAL;   RESULT: 2
SELECT LENGTHB('학교') FROM DUAL;  RESULT: 4

-- LANGUAGE : AMERICAN_AMERICA.US7ASCII
SELECT LENGTH('학교') FROM DUAL;   RESULT: 4


-- 문자열에서 특정 문자나 문자열의 위치 INSTR[B](string1, [char||string], start_position, n_counted)
SELECT INSTR('ORACLE PROJECT', 'R', 1, 1) INSTR1, INSTR('ORACLE PROJECT', 'R', 1, 2) INSTR2,
INSTR('ORACLE PROJECT', 'R', 1, 3) INSTR3 FROM DUAL;
SELECT INSTR('CORPORATE FLOOR', 'OR', 3, 2) INSTR, INSTRB('CORPORATE FLOOR', 'OR', 3, 2) INSTRB FROM DUAL;
SELECT INSTR('하늘 아래 하늘이 또 있겠는가.', '하늘', 1, 2) 하늘1,INSTRB('하늘 아래 하늘이 또 있겠는가.', '하늘', 1, 2) 하늘2 FROM DUAL;

   

-- 병합 (||)

다음 쿼리문은 SP_GDS, SP_COMP_CODE, MALL_DESC를 '|'를 구분자로 하여 병합한다.

SELECT DISTINCT(SP_GDS) || '|' || SP_COMP_CODE || '|' || MALL_DESC
FROM TCA_SP_ACMP
WHERE SP_TRD_DTIME BETWEEN TO_DATE('20070101', 'YYYYMMDD') AND
TO_DATE('20070131', 'YYYYMMDD') AND SP_COMP_CODE='0210';


-- SYSTEM 시간
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') "SYSDATE" FROM DUAL;

   

-- 주어진 날짜가 속하는 월의 마지막 날짜
SELECT TO_CHAR(LAST_DAY(SYSDATE), 'YYYY-MM-DD HH24:MI:SS') "LAST_DAY" FROM DUAL;

   

-- 주어진 두 날짜간의 기간을 월 단위로 계산 
-- MONTHS_BETWEEN(date1, date2)  : IF date1 > date2  THEN +

9i에서는 요로케...

SELECT MONTHS_BETWEEN(
 TO_DATE('2006/12/26', 'YYYY/MM/DD'), TO_DATE('2007/01/25','YYYY/MM/DD')) "MONTHS_BETWEEN(-1)",
 MONTHS_BETWEEN(
 TO_DATE('2006/01/13', 'YYYY/MM/DD'), TO_DATE('2005/11/13', 'YYYY/MM/DD')) "MONTHS_BETWEEN(+)"
FROM DUAL;

   

10g에서는 요로케...

SELECT MONTHS_BETWEEN('2006/12/26', '2007/01/25') "MONTHS_BETWEEN(-)",
MONTHS_BETWEEN('2006/01/13', '2005/11/13') "MONTHS_BETWEEN(+)" FROM DUAL;
SELECT ROUND(MONTHS_BETWEEN('2006/12/28', '2006/12/01'), 1) FROM DUAL;

   

   

   

-- 월단위 계산
SELECT ADD_MONTHS(SYSDATE, 12) "ADD_MONTHS(+)", ADD_MONTHS(SYSDATE, -12) "ADD_MONTHS(-1)" FROM DUAL;

   

-- 주어진 날짜를 기준으로 주어진 요일이 처음 오는 날짜
-- 일요일:1 ~ 토요일:7
SELECT SYSDATE, NEXT_DAY(SYSDATE, '일요일') "NEXT_DAY 1",

NEXT_DAY(SYSDATE, 1) "NEXT_DAY 2" FROM DUAL;

LANGUAGE 설정에 따라 영문으로도..

SELECT NEXT_DAY(SYSDATE, 'Sunday') "NEXT_DAY 1" FROM DUAL;

   


-- NUMBER와 DATE를 문자타입으로 변환
SELECT TO_CHAR(123456789) "NUMBER", TO_CHAR(SYSDATE,'YYYY/MM/DD HH24:MI:SS') "DATE" FROM DUAL;

   

-- 문자를 숫자로 변환
SELECT TO_NUMBER('123456789') "TO_NUMBER1",
TO_NUMBER('123,456.9', '999,999.9') "TO_NUMBER2",
TO_NUMBER('1,234,567', '9G999G999') "TO_NUMBER3" FROM DUAL;

   

-- 문자형 데이타를 DATE형으로 변환
SELECT TO_DATE('20020824', 'YYYYMMDD') "TO_DATE1",
TO_DATE('2002-08-24', 'YYYY-MM-DD') "TO_DATE2",
TO_DATE('200208', 'YYYYMM') FROM DUAL;

   

-- 평균값 구하기
SELECT AVG(HEIGHT), AVG(WEIGHT) FROM PERSONNEL;

   

-- 최대값 최소값
SELECT MAX(EMPNO), MAX(EMP_NAME), MIN(EMPNO), MIN(EMP_NAME) FROM PERSONNEL;

   

-- 합계 구하기
SELECT SUM(WEIGHT) FROM PERSONNEL;

   

-- 조회 범위의 조회 건수
SELECT COUNT(*), COUNT(EMPNO), COUNT(JIKCH_CODE) FROM PERSONNEL;

   

-- NULL 값 치환
SELECT EMPNO, EMP_NAME, HOBBY 취미, NVL(WELL, '없음') 특기
FROM PERSONNEL WHERE EMPNO BETWEEN '98001' AND '98005';

   

-- 연속 조건문
-- DECODE(a, b, c, d)  a가 b면 c고, 아니면 d
-- DECODE(a, b, c, d, e, f, g, h ....) a가 b면 c고, d면 e고, f면 g고 h면 ...
-- DECODE(a, b, c, DECODE(e, f, g, h))
SELECT EMPNO, EMP_NAME, DECODE(HT_CODE, '1', '현재원', '2', '휴직원', '퇴사') HT_CODE
FROM PERSONNEL WHERE EMPNO BETWEEN '98071' AND '98080';

   

-- 오라클 환경변수 값 구하기
SELECT USERENV('LANGUAGE') "LANGUAGE", USERENV('TERMINAL') "TERMINAL",
USERENV('SESSIONID') "SESSIONID" FROM DUAL;

   

-- 주어진 데이타중 최대값 최소값 구하기
SELECT GREATEST(132,33 ,45,99,22, 32, 77, 12) GREATEST, LEAST(132,33 ,45,99,22, 32, 77, 12) FROM DUAL;
SELECT GREATEST('가', '나', '다', '라', '마') GREATEST1, GREATEST('가', '나', '다', '라', '마', '마마') GREATEST2,
LEAST('가', '나', '다', '라', '마') FROM DUAL;

   

-- UID, USER
SELECT UID, USER FROM DUAL;
 

-- TO_CHAR : NUMBER와 DATE를 문자로 변환

TO_CHAR(n)

TO_CHAR(n, format)

n(number)

format

format

1000

'9,999.99'

'9G999D99'

1234567.890

'9,999,999.999'

'9G999G999D999'

3.5

'9,999.99'

'9G999D99'

1234

'999,999'

'999G999'

   

TO_CHAR(date, format)

date

format

format sample

sysdate

'YYYYMMDD'

'20070321'

'YYYY/MM/DD'

'2007/03/21'

'YYYY-MM-DD'

'2007-03-21'

'YYYYMMDD HH24MISS

'20070321 215710'

'YYYYMMDD HHMISS AM'

'20070321 095710 PM'

'YYYY/MM/DD HH24:MI:SS'

'2007/03/21 21:57:10'

'YYYY/MM/DD HH24:MI:SS:SSSSS'

'2007/03/21 21:57:10:78800'

   

SELECT TO_CHAR(1234567.891) TO_CHAR1,

TO_CHAR(1234567.891, '999') TO_CHAR2,

TO_CHAR(1234567.891, '9,999,999') TO_CHAR3,

TO_CHAR(1234567.891, '0.0000') TO_CHAR4,

TO_CHAR(1234567.891, '9,999,999.0000') TO_CHAR5,

TO_CHAR(123, '9,999.00') TO_CHAR6,

TO_CHAR(123, '9,999.99') TO_CHAR7

FROM DUAL;

   

SELECT TO_CHAR(1234567.891, '9G999G999') TO_CHAR1,

    TO_CHAR(1234567.891, '0D0000') TO_CHAR2,

    TO_CHAR(1234567.891, '9G999G999D0000') TO_CHAR3,

    TO_CHAR(123, '9G999D00') TO_CHAR4,

    TO_CHAR(123, '9G999D99') TO_CHAR5

FROM DUAL;

   

SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD') TO_CHAR1,

    TO_CHAR(SYSDATE, 'YYYY/MM') TO_CHAR2,

    TO_CHAR(SYSDATE, 'YYYY') TO_CHAR3,

    TO_CHAR(SYSDATE, 'DD')    TO_CHAR4,

    TO_CHAR(SYSDATE, 'DAY') TO_CHAR5,

    TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI:SS') TO_CHAR6,

    TO_CHAR(TO_DATE('20070321', 'YYYYMMDD'), 'YYYY-MM-DD') TO_CHAR7,

    TO_CHAR(TO_DATE('20070321', 'YYYYMMDD'), 'YYYYMMDD HHMISS') TO_CHAR8,

    TO_CHAR(SYSDATE, 'MONTH') TO_CHAR9,

    TO_CHAR(SYSDATE, 'YEAR') TO_CHAR10,

FROM DUAL;

Posted by brent.lee


문자열 처리 함수(Character Functions)

1. CONCAT(char1, char2)

  - CONCAT 함수는 Concatenation 약자로 문자를 결합하는 역할을 한다.
     ( "||"
연산자와 같은 역할을 한다. )

 SQL>SELECT CONCAT('Oracle', ' Korea') NAME FROM dual ;

   NAME
   -------------
   Oracle Korea

 

2. INITCAP(char)

  - 주어진 문자열의 단어의 번째 문자를 대문자로 변환. 단어는 공백으로 분리.
 
SQL>SELECT INITCAP('kim jung sick') NAME FROM dual ;

NAME
-------------
Kim Jung Sick
 


3. LOWER(char)

  - 문자열을 소문자로 변환.

SQL>SELECT LOWER('KIM JUNG SICK') NAME FROM dual ;

NAME
-------------
kim jung sick

 

4. UPPER(char)

  - 문자열을 대문자로 변환 시켜 줍니다.

SQL>SELECT UPPER('kim jung sick') NAME FROM dual ;

NAME
--------------
KIM JUNG SICK
 


5. LPAD(char1, n [,char2])

  - 왼쪽에 문자열을 끼어 놓는 역할을한다.
n
반환되는 문자열의 전체 길이를 나타내며,
char1
문자열이 n보다 경우 char1 n 문자열 만큼 반환함.
 
 SQL>SELECT LPAD('JUNG-SICK', 10, '*') NAME FROM dual ;

NAME
------------
 *JUNG-SICK
 


6. RPAD(char1, n [,char2])

  - LPAD 반대로 오른쪽에 문자열을 끼어 놓는 역할을 한다.
 
SQL>SELECT RPAD('JUNG-SICK', 10, '*') NAME FROM dual ;

NAME
------------
JUNG-SICK*
 


7. SUBSTR(char, m ,[n])

  - SUBSTR함수를 이용하여 m 번째 자리부터 길이가 n개인 문자열을 반환한다.
m
음수일 경우에는 뒤에서 M번째 문자부터 반대 방향으로 n개의 문자를 반환한다.
 
SQL>SELECT SUBSTR('JUNG-SICK', 3, 3) NAME FROM dual ;

NAME
-----------
NG-

-- 뒤에서부터 자를 경우
SQL>SELECT SUBSTR('JUNG-SICK', -3, 3) NAME FROM dual ;

NAME 
-----------
ICK
 


8. LENGTH(char1)

  - 문자열의 길이를 리턴.
 
SQL>SELECT LENGTH('JUNG-SICK') TEST FROM dual ;

TEST
----------
9
 


9. REPLACE(char1, str1, str2)

  - REPLACE 문자열의 특정 문자를 다른 문자로 변환 한다.  

SQL> SELECT REPLACE('JACK and JUE','J','BL') "Changes" FROM DUAL;
 
Changes
--------------
BLACK and BLUE
 
 
 
SQL> SELECT REPLACE('JACK and JUE','JA','BL') "Changes" FROM DUAL
 
Changes
------------
BLCK and JUE
 
 
--
대소문자를 구분한다는 것을 알수 있음.
SQL>SELECT REPLACE('JACK and JUE','j','BL') "Changes" FROM DUAL
 
Changes
------------
JACK and JUE
 


10. INSTR

   - 문자열이 포함되어 있는지를 조사하여 문자열의 위치를 반환한다.
   -
지정한 문자열이 발견되지 않으면 0 반환됨.  

-- 지정한 문자 OK 발견되지 않아서 0 반환 .
SQL>SELECT INSTR('CORPORATE FLOOR','OK')  "Instring" FROM DUAL
 
Instring
----------
0


-- OR 있는 위치 2 반환 한다. 왼쪽부터 비교를 한다는 것을 있음.
SQL>SELECT INSTR('CORPORATE FLOOR','OR')  "Instring" FROM DUAL
 
Instring
----------
2
 

-- 왼쪽에서 3번째부터 시작을 해서 비교를 한다. 2번째 OR 위치가 반환 .
SQL>SELECT INSTR('CORPORATE FLOOR','OR', 3)  "Instring" FROM DUAL
 
Instring
----------
5


-- 왼쪽에서 3번째부터 시작해서 비교를 하는데 
OR
번째 검색되는 지점의 위치를 반환 한다.
SQL> SELECT INSTR('CORPORATE FLOOR','OR', 3, 2)  "Instring" FROM DUAL;
 
Instring
----------
14
 
 


11. TRIM

   - 특정한 문자를 제거 한다
   -
제거할 문자를 입력하지 않으면 기본적으로 공백이 제거 .
   -
리턴값의 데이터타입은 VARCHAR2.

-- 0 제거
SQL>SELECT TRIM(0 FROM 0009872348900)  "TRIM Example" FROM DUAL;
 
TRIM Example
------------
98723489
 
 
--
어떤 문자도 입력하지 않으면 기본적으로 공백이 제거
SQL>SELECT NVL(TRIM ('  '),'
공백')  "TRIM Example"  FROM DUAL
 
TRIM Example
------------
공백
 
-- TRIM
사용한 위에 예제와 사용하지 않은 아래 예제의 결과 값이 다름을 있다.SQL>SELECT NVL('  ','공백')  "TRIM Example" FROM DUAL
 
TRIM Example
------------


12. LTRIM

SQL>SELECT LTRIM('xyxXxyLAST WORD','xy') "LTRIM example"  FROM DUAL;
 
LTRIM example
------------
XxyLAST WORD
 
 
13. RTRIM

SQL>SELECT RTRIM('BROWNINGyxXxy','xy') "RTRIM example"     FROM DUAL;

RTRIM examp
-----------
BROWNINGyxX

Posted by brent.lee


Windows 2003에 Oracle 11gR2 설치 후 로컬피씨에서 sysdba 계정으로 접속시 다음과 같은 에러가 발생했다.

 

 

 

C:\>sqlplus / as sysdba    

SQL*Plus: Release 11.2.0.1.0 Production on 목 8월 16 09:40:53 2012    

Copyright (c) 1982, 2010, Oracle.  All rights reserved.    

ORA-01031 : insufficient privileges

 

이를 해결하는 방법은 다음과 같다.

1. 제어판 > 관리 도구 > 컴퓨터 관리를 실행

 

2. 로컬 사용자 및 그룹 > 사용자를 선택

3. 우측의 이름 컬럼 중 현재 사용하고 있는 계정을 선택후 우클릭하여 속성을 선택

4. 소속 그룹탭을 선택 후 추가 버튼을 클릭

 

5. 고급을 실행 후 dba_ora 그룹을 찾아서 추가

 

6. ora_dba 그룹이 추가된 화면

 

 

위와 같이 정상적으로 ora_dba그룹이 추가되었다면 정상적으로 sysdba 계정으로 접속이 가능하다.

 

C:\>sqlplus / as sysdba

 SQL*Plus: Release 11.2.0.1.0 Production on 목 8월 16 09:40:53 2012

 Copyright (c) 1982, 2010, Oracle.  All rights reserved.

   

다음에 접속됨:

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

 

참고 : http://luckysoftware.wordpress.com/2012/08/11/cannot-login-to-oracle-using-sqlplus-as-sysdba/

Posted by brent.lee


 

EXEC sp_attach_db @dbname = N'dbname'   -- 복원할 DB의 이름
   , @filename1 = N'E:\data\home\database\MSSQL2005\MSSQL.1\MSSQL\Data\dbname_log.ldf'   -- LDF 파일 위치
   , @filename2 = N'E:\data\home\database\MSSQL2005\MSSQL.1\MSSQL\Data\dbname.mdf'   --  MDF 파일 위치

 

위와 같이 기존에 스크립트에서 파일을 attach 시키던것이 2012 에서는 아래 그림같이..클릭만으로 attach되도록 바뀌었다..

업무상 이기능을 많이 쓰지는 않겠지만.. 개발이나 테스트때마다 mdf 파일들 스크립트로  attach 하는것이 나름 귀찮았는데..

갈수록 편해지는듯

 

 

 

 아래 Attach 화면에서 mdf 파일만 Add 하면 끝난다...

 

Transact SQL 사용시...

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

CREATE DATABASE MyAdventureWorks
    ON (FILENAME = 'C:\MySQLServer\AdventureWorks_Data.mdf'),
    (FILENAME = 'C:\MySQLServer\AdventureWorks_Log.ldf')
    FOR ATTACH;

http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(SQL11.SWB.ATTACHDATABASE.F1)&rd=true

Posted by brent.lee


TortoiseSVN

                   http://tortoisesvn.net/

 

 

Posted by brent.lee


http://wiki.javajigi.net/pages/viewpage.action?pageId=68

IoC 컨테이너와 의존성 삽입 패턴

Summary : Spring 프레임워크를 이해하기 위해서는 먼저 IoC 패턴에 대해 이해하고 있어야 한다. IoC 패턴을 이해할 경우 Spring이 가지고 있는 기본적인 Container 개념을 이해할 수 있다. 이번 강좌에서는 VSSH 프로젝트에서 진행한 IoC 패턴 강좌를 통하여 IoC 패턴에 대하여 이해할 수 있도록 한다.

들어가기에 앞서

이 글은 마틴 파울러(Martin Fowler)의 IoC 패턴에 대한 글을 토대로 스프링의 기반이 되는 IoC 패턴에 대해 소개할 목적으로 작성된 것입니다.
대부분의 내용은 아래 URL에 있는 마틴 파울러의 글을 편역한 것입니다.

참고자료 1. http://martinfowler.com/articles/injection.html : 중간 중간에 있는 IoC 컨테이너에 대한 설명은 TheServerSide.com에 등록된 Rod Johnson의 "Introducing the Spring Framework"에서 소개된 내용입니다

참고자료 2. http://www.theserverside.com/news/thread.tss?thread_id=21893

이 글타래는 마틴 파울러의 글을 순수하게 번역한 자료가 아닙니다. 번역한 원문을 읽어보실 분은 아래의 정보를 참고하세요.

원문 번역보기 1. 일본어 번역인 아래 링크를 파란 일본어 번역기를 이용하시면 전체 번역을 보실 수 있습니다.
http://www.kakutani.com/trans/fowler/injection.html

원문 번역보기 2. 네이버 "자바프레임워크 까페"에는 오버가이님이 번역하신 글도 있습니다. 번역한 글

IoC 컨테이너와 의존성 삽입 패턴(Inversion of Control Containers and the Dependency Injection pattern )

자바 커뮤니티에서는 다른 프로젝트에서 개발된 컴포넌트를 조립해서 응집력 있는 어플리케이션의 개발이 가능하도록 도와주는 경량급 컨테이너(Lightweight Container)에 대해 높은 관심을 보이고 있습니다.

경량급 컨테이너가 컴포넌트를 엮어주는 일을 수행하는 밑바탕에는 제어 역행화(Inversion of Control)라는 개념이 깔려 있습니다. 제어 역행화는 용어만으로 그 의미를 파악하는데 한계가 있기 때문에, 또 다른 말로 의존성 삽입(Dependency Injection) 이라고도 불려집니다. 이 글에서는 제어 역행화 패턴의 동작 원리를 설명하고, 대안이 되는 서비스 로케이터(Service Locator) 패턴과 비교해보도록 하겠습니다.

여기서 중요한 것은 제어 역행화 패턴과 서비스 로케이터 패턴 중 어떤 것을 선택할 것인지에 대한 고민 보다는, 컴포넌트의 설정을 그것의 사용에서 분리해야 한다는 원칙(The principle of separating configuration from use)을 이해하는 것입니다.

일반적 제어흐름을 갖는 작은 예제

우선 특정 기능을 가진 객체를 이용해서 어떤 로직을 처리하는 전형적인 프로그래밍 방식에 어떤 문제점이 있는지 살펴보기 위해 작은 예제를 하나 살펴보도록 합시다.

이 예제는 어느 특정 감독이 만든 영화를 리스트하는 프로그램(MovieLister)입니다.

MovieLister.java(moviesDirectedBy() 메소드 구현)
class MovieLister... 
  public Movie[] moviesDirectedBy(String arg) { 
    // 영화 정보를 검색하는 프로그램에게 모든 영화정보를 리스트로 가져오라고 요청 
    List allMovies = finder.findAll(); 
    for (Iterator it = allMovies.iterator(); it.hasNext();) { 
      // 각각의 영화를 Iterator를 이용해서 추출해 냄 
      Movie movie = (Movie) it.next(); 
      // 선택된 영화의 감독이 찾고자 하는 감독인지 비교 후 불일치하면 삭제 
      if (!movie.getDirector().equals(arg)) it.remove(); 
    } 
    // 해당 감독의 영화만 남겨진 리스트를 배열로 변환시켜 전달함 
    return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]); 
  }

MovieLister는 모든 영화 정보를 구해오기 위해 finder란 객체를 이용하고 있습니다. 코드에서 보여지는 finder 객체는 findAll()이란 메소드가 구현되어 있어야 합니다. MovieLister는 finder 객체가 어떤 방식으로 영화 정보를 가져오는지에는 관심이 없습니다. 그저 findAll()을 호출하면, 모든 영화 정보(Movie)를 담은 리스트가 넘어오면 되는 겁니다. 이를 위해 MovieFinder라는 인터페이스를 우선 만들도록 하겠습니다.

MovieFinder.java
public interface MovieFinder { 
  List findAll(); 
}

위에서 작성한 MovieLister가 제대로 동작하기 위해서는 MovieFinder 인터페이스를 구현할 구현 클래스가 필요합니다. 영화 정보가 콜론( : )으로 구별된 CSV형태의 텍스트 파일에 담겨 있다고 가정해 봅시다.

movies1.txt
#영화제목:감독:주연배우리스트:출시년도:장르 
80일간의 세계일주:프랭크 코라시:성룡, 스티브 쿠간:2004:액션 어드벤처 
귀신이 산다:김상진:차승원,장서희:2004:코미디 
꽃피는 봄이 오면:류장하:최민식,김호정:2004:드라마

그렇다면 MovieFinder의 구현 클래스로 ColonDelimitedMovieFinder란 클래스를 작성했겠죠? 그런 다음 MovieLister의 코드에 finder가 어떤 클래스의 인스턴스인지를 명시할 것입니다. 아래의 경우에는 MovieLister 클래스가 생성될 때 MovieFinder의 구현을 초기화하도록 했습니다. (또는 setMovieFinder() 같은 setter()를 만들어 초기화 할겁니다.)

이렇게 초기화해놓지 않으면.. 다시 말해 MovieFinder가 어떤 구현 클래스의 인스턴스 인지가 결정되지 않으면, moviesDirectedBy() 메소드 실행 중에 NullPointerException이 발생하기 때문에 어쩔 수 없는 일입니다.

MovieLister.java (finder 초기화)
class MovieLister... 
  private MovieFinder finder; 
  public MovieLister() { 
    // finder가 MoveFinder 인터페이스를 따르는 어떤 구현인지를 명시함 
    // 이로써 MovieFinder는 인터페이스와 그 구현 모두에 의존관계를 가짐. 
    finder = new ColonDelimitedMovieFinder("movies1.txt"); 
  }

이 예제는 아래의 클래스 다이어그램처럼 구성됩니다. MovieLister의 기능 구현에 MovieFinder 타입의 객체가 사용된다는 사실, 그리고 그 MovieFinder가 구체적으로 어떤 구현 클래스의 인스턴스인지가 아래와 같이 연결되어 있습니다.

여기에서 어떤 변화가 없다면, 이 프로그램은 충분히 만족할만 합니다. 그런데 만일 영화 정보를 기록하는 수단으로 파일이 아닌 DB를 이용해 달라는 새로운 요구 사항이 생긴다면? 또는 XML로 기록해달라거나, 영화 정보를 제공하는 또 다른 프로그램과 인터페이스 시켜달라거나 하는 요구 사항이 생긴다면?

다행히 이런 확장을 고려해서 미리 인터페이스를 만들어뒀기 때문에 XMLMovieFinder나 RDBMovieFinder 같은 기능 확장은 쉽게 처리됩니다. moviesDirectedBy() 메소드 역시 단 한 줄도 수정할 필요가 없구요. 그럼에도 불구하고 MovieLister.java의 코드는 재작성/재컴파일/재배포 과정을 거쳐야 합니다.

MovieLister.java (finder 초기화 정보 변경)
class MovieLister... 
  private MovieFinder finder; 
  public MovieLister() { 
    // 구현이 추가될 경우, 의존관계로 인해 초기화 루틴이 변경되어야 함. 
    finder = new XMLMovieFinder("movies1.xml"); 
  }

왜 이런 현상이 생긴걸까요? 그것은 MovieLister가 MovieFinder라는 인터페이스와 그 구현 모두에 의존하기 때문입니다.

변화에도 코드 수정 및 재배포가 필요없도록 의존성을 표현하는 방법은?

대부분의 경우 이를 해결하기 위해 팩토리 패턴을 적용하는 경우가 많습니다. 하지만 팩토리 패턴이 구현 객체에 대한 의존성 문제를 완전히 해결해주진 못합니다. 인터페이스 정보만을 참고해서 프로그램을 작성하는 것은 당연히 바람직한 현상입니다. 그렇다면, 인터페이스 구현 클래스의 인스턴스는 어떻게 생성하는 것이 좋을까요?
마틴 파울러는 그의 저서 "Patterns of Enterprise Application Architecture"에서 이를 해결하기 위해 "플러그인 (Plugin)"이라는 개념을 소개합니다. (참고 : http://martinfowler.com/eaaCatalog/plugin.html)

플러그인은 구현 객체에 대한 의존성 정보를 설정 파일에 담아 실시간으로 관리함으로써, 어플리케이션을 구성하는 각각의 컴포넌트들이 구체적인 구현 클래스를 모르고도 상호작용 할 수 있도록 합니다. (Plugin solves both problems by providing centralized, runtime configuration.) 그럼 어떻게 이러한 동작이 가능한 것일까? 그 기본 원리가 바로 *제어 역행화(Inversion of Control) 패턴*입니다.

제어 역행화 패턴과 IoC 컨테이너

IoC(Inversion of Control)을 제어 역행화라고 번역했으나 제어의 반전이라는 말로도 즐겨쓰는 듯 합니다. IoC는 직관적이지 못하기 때문에 Dependency Injection이라고도 불려집니다. Dependency Injection을 저는 의존성 삽입이라고 표현했는데요, 요즘은 의존성 주입이라는 말을 더 즐겨쓰는 듯 합니다. 다소 불편이 있더라도 양해해 주세요. 이 글은 제가 처음에 이해한대로 용어를 사용하고 있지만, 공론이 형성되면 거기에 따라 변경하겠습니다.

제어 역행화는 말 그대로 제어가 일반적인 흐름을 따르지 않고, 반대로 흘러간다는 뜻입니다. 각각의 프로그램이 가지고 있던 구현 객체에 대한 정보가 이젠 프레임워크에서 관리되는 것이죠. 제어 역행화(Inversion of Control)를 구현하는 프레임워크를 IoC 컨테이너라고 부릅니다. 일단 그림을 통해 간단히 개념부터 짚고 넘어가봅시다.

앞에서 살펴본 일반적인 제어흐름 그림과 비교해서 살펴보면 이해가 훨씬 쉬울겁니다. 이전의 MovieLister는 MovieFinder라는 인터페이스와 그 구현 MovieFinderImple에 모두 영향을 받았던 사실. 기억나죠? 하지만 이제 어떤 MovieFinderImpl이 만들어져야 하는지를 MovieLister는 전혀 알지 못합니다. 해당 객체의 생성을 Assembler라는 독립된 객체가 담당하기 때문입니다. 그럼 MovieLister는 어떻게 MovieFinderImpl을 이용할 수 있을까요? 그림에서 보이는 것처럼 Assembler에 의해서 생성된 MovieFinderImpl이 알아서 MovieLister를 찾아가서 삽입(Injection) 됩니다.

그림에서 보이는 Assembler 역할을 하는 것이 바로 IoC 컨테이너입니다. IoC 개념을 지지하는 많은 개발자들은 제어 역행화라는 용어가 직관적이지 않다는데 동의했습니다. 그래서 더 이해하기 쉬운 용어에 대한 논의를 거듭한 결과, 의존성 삽입이라는 용어를 만들어냈습니다. 의존성(Dependency)이란 어떤 기능을 구현하는데 있어 필요한 정보들을 전체적으로 표현하는 단어입니다.

예를 들면, 그 기능에서 사용되는 것이 구체적으로 어떤 객체인지.. 그리고 그 기능을 수행하는데 필요한 초기화 값은 무엇인지..

그런데 몇 가지 의문점이 생깁니다.

  • 질문-1) IoC 컨테이너는 무엇을 근거로 해당 인터페이스의 구현 객체 중 하나를 선택하는 것일까요?
  • 질문-2) 선택된 구현 객체를 생성시켜, 어느 클래스가 그 구현 객체를 사용하는지를 어떻게 판단할까요?
  • 질문-3) 사용자 클래스에 구현 객체를 연결시키는 방법은 무엇일까요?
    질문-1과 질문-2에 대한 답은 IoC 컨테이너의 설정 정보에 있습니다. IoC 컨테이너는 XML 방식의 설정 파일을 이용해서, 어떤 구현 객체가 생성되어야 하는지.. 그리고 생성된 구현 객체가 어떤 클래스에서 참조되는지에 대한 정보를 담도록 강제화합니다. (Spring의 예를 들어 설정 정보를 살펴보자면, 아래와 같은 형태가 되겠죠?)
    <bean id="movieLister" class="MovieLister"> 
        <property name="movieFinder"> 
            <ref bean="cdMovieFinder"/> 
        </property> 
    </bean> 
    <bean id="cdMovieFinder" class="ColonDelimitedMovieFinder"> 
        <property name="data"><value>movies1.txt</value></property> 
    </bean>

이제 질문-3에 대한 답을 구해봅시다. 어떻게 생성된 구현 객체를 사용자 클래스에 삽입시키는 걸까요?

이 방법은 클래스에서 사용되는 객체 초기화를 어떻게 했었는지를 떠올려보면 쉽게 이해할 수 있습니다. 객체지향에서 상속보다 위임이 더 나은 설계임은 이미 널리 알려진 사실입니다.

대부분의 자바 코드는 아래와 같이 특정 컴포넌트를 사용해서 자신의 기능을 구현합니다. 이때 차후에 발생할 기능확장을 고려해서 타입 정보를 분리해내는 것이 일반적입니다. 객체지향에서 순수한 타입(ADT)이란 결국 어떤 기능을 수행할 수 있는가, 즉 오퍼레이션(Operation)들의 집합이죠. 그래서 What을 표현하기 위한 인터페이스를 위에 만들고, How는 What의 한 사례이기 때문에 인터페이스를 따르는 구현 클래스를 만들게 되죠. 이러한 원리를 누구나 다 알고 있기 때문에, 대개의 경우 코드가 아래와 같은 형태가 될 것입니다.

Class UserClass { 
    private IComponent instance; 
    public void userClassMethod() { 
        instance.componentMethod();   
        doSomeThing(); 
    } 
}

여러분은 instance를 어떻게 초기화하시나요? 일반적으로 생성자에서 초기화를 시켜주거나 setter를 이용하죠?

Class UserClass { 
    private IComponent instance; 

    public UserClass() { // (1) 이렇게 생성자에서 초기화를 시켜주기도 합니다. 
        this.instance = new ComponentImpl(); 
    } 

    public void userClassMethod() { 
        instance.componentMethod(); 
        doSomeThing(); 
    } // (2) 아니면 이렇게 setter를 만들고 호출하던지요.. 

    public void setIComponent(IComponent instance) { 
        this.instance = instance; 
    } 
}

또 다른 방법이 있다면 객체 초기화를 담당할 인터페이스를 만들어서, 모든 클래스가 반드시 해당 인터페이스를 구현하도록 할 수도 있을 겁니다. 예를 들어 initialize() 같은 메소드가 포함된 인터페이스를 생각해볼 수 있겠네요..

IoC 컨테이너는 자신의 표준 설정 방법에 따라 의존성 정보를 확인하고, 그에 따라 객체 생성 및 초기화를 대신해주는 녀석입니다. 위에서 언급한 생성자, Setter, 인터페이스 이용 중 어떤 방식으로 구현 객체(의존성)을 사용자 객체에 삽입하느냐에 따라 의존성 삽입의 유형이 결정됩니다.

의존성 삽입의 3가지 유형

  • 유형 1. 생성자를 이용한 의존성 삽입 (Constructor Injection : type 1 IoC)
  • 유형 2. Setter() 메소드를 이용한 의존성 삽입 (Setter Injection : type 2 IoC)
  • 유형 3. 초기화 인터페이스를 이용한 의존성 삽입 (Interface Injection : type 3 IoC)

의존성 삽입이 구현되어 컴포넌트를 조립(플러그인)해서 응집력 있는 어플리케이션의 개발이 가능하도록 도와주는 어셈블러의 구현이 IoC 컨테이너이며, 다른 말로 경량급 컨테이너(Lightweight Container)라고도 합니다.

스프링이 바로 IoC 컨테이너이구요, 또 다른 종류로는 PicoContainer와 아파치의 Avalon, 그리고 HiveMind 등이 있습니다. 그 중에서 현재 가장 널리 사용되고 있는 것은 스프링(Spring)과 피코 컨테이너(PicoContainer)입니다.

피코 컨테이너는 type 1 IoC, 즉 생성자를 이용한 의존성 삽입이 일반적이구요, 스프링 프레임워크는 type 2 IoC, 즉 Setter() 메소드를 이용한 의존성 삽입이 일반적입니다.

글을 마무리하며..

저는 스프링을 접하면서 IoC 개념이 쉽게 이해되지 않아 고생이 심했습니다. Inversion of Control? 마틴 파울러의 글을 다섯 번이 넘게 반복해서 읽고 나서야 겨우 감이 잡히더군요..

기본 개념을 잡는데 저처럼 힘들어하실 분들을 위해 개념위주로 간단하게 기록을 남겨봅니다.

글에 실수가 있더라도 너그럽게 이해해주세요..

뭐든 기본 개념이 제일 중요한데, 사실 재미도 없고.. 제대로 설명하기도 어렵고...

그래서인지 이번 글은 진도가 안나가네요.. 그냥 이쯤에서 만족하고 접겠습니다.

더 자세한 설명이 필요한 분은 마틴 파울러의 원본글과 앞서 소개한 번역 자료들을 이용하시길..

이 강좌의 출처는 OpenSeed 프로젝트입니다. 강좌를 공유해주신 김승권님께 감사 드립니다.

강좌에 대하여

작성자 : 김승권
작성일 : 2005년 2월 23일

문서이력 :

  • 2005년 2월 23일 김승권 문서 최초 생성

참고 자료

 

Posted by brent.lee


 

Posted by brent.lee


http://msdn.microsoft.com/ko-kr/library/0feaad6z(v=vs.110).aspx

http://msdn.microsoft.com/ko-kr/library/kb4wyys2(v=vs.100).aspx?appid=dev10idef1&amp;l=en-us&amp;k=k(cs.projectpropertiesbuild);k(targetframeworkmoniker-&quot;.netframework,version=v4.0&quot;)&amp;rd=true

 

 

#define을 직접 쓸수는 없지만..

/define:name[;name2] 등과 같이 선언해서

#if (name) 로 사용 가능

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

// preprocessor_define.cs

// compile with: /define:xx

// or uncomment the next line

// #define xx

using System;

public class Test

{

     public static void Main()

{

#if (xx)

Console.WriteLine("xx defined");

#else

Console.WriteLine("xx not defined");

#endif

}

}

 

 

참고

http://www.davidarno.org/c-howtos/define-and-other-c-preprocessor-directives/

 

'개발 > C#' 카테고리의 다른 글

C# 전처리기 - 펌  (0) 2013.05.12
Microsoft Visual Studio 2010 서비스 팩 1  (0) 2013.05.11
Posted by brent.lee

2013. 5. 12. 15:34 개발/C#

C# 전처리기 - 펌



1. #if

  흔히 디버그 빌드용으로 컴파일하거나 특정 구성용으로 컴파일 할때 주로 사용됩니다.

  #if로 시작한 조건부 지시문은 명시적으로 #endif 지시문으로 종료해야합니다.

   

  Example )

 #define DEBUG
#define VC_V7
using System;
public class MyClass 
{
   public static void Main() 
   {

      #if (DEBUG && !VC_V7)
         Console.WriteLine("DEBUG is defined");
      #elif (!DEBUG && VC_V7)
         Console.WriteLine("VC_V7 is defined");
      #elif (DEBUG && VC_V7)
         Console.WriteLine("DEBUG and VC_V7 are defined");
      #else
         Console.WriteLine("DEBUG and VC_V7 are not defined");
      #endif
   }
}


OutPut : DEBUG and VC_V7 are defined

2. #else

 #if의 선택적 요소일때 #else를 사용합니다.

3. #elif

프로그램용어로 받아들이기 쉽게 하자면 else if 문입니다. 복합 조건부 지시문을 만들때 사용합니다.

4. #endif

#if 지시문으로 시작한 조건부 지시문의 끝을 지정합니다.

   

5. #define

사용자 기호를 정의합니다. 이때 정의한 기호를 #if 지시문에 전달되는 식으로 사용하면 식이 true로 계산됩니다.

ㅇ. 기호를 사용하여 컴파일 조건을 지정할 수 있습니다. 이는 #if , #elif로 테스트 할수 있습니다.

또한 conditional 특성을 사용하여 조건부 컴파일을 수행 할 수도 있습니다.

ㅇ. 기호를 정의할 수 있지만 해당 기호에 값을 대입할 수는 없습니다. 지시문이 아닌 모든 명령어를 사용하려면 #define지시문이 먼저 파일에 나타나야합니다.

ㅇ. /define 컴파일러 옵션으로 기호를 정의할 수도 있습니다. 또한 #undef로 기호를 정의하지 않을수도 있습니다. /define , #define으로 정의하는 기호는 같은 이름의 변수와 충돌하지 않습니다. 즉,변수 이름을 전처리기 지시문에 전달해서는 안되며 기호는 전처리기 지시문으로만 계살 할수 있습니다.

#define으로 만든 기호의 범위는 해당 기호가 정의된 파일입니다.

6. #undef

 기호를 정의하지 않습키다. 이때 정의하지 않은 기호를 #if지시문의 식으로 사용하면 식이 false로 계싼됩니다.

   

Example)

// preprocessor_undef.cs
// compile with: /d:DEBUG
#undef DEBUG
using System;
public class MyClass 
{
   public static void Main() 
   {
      #if DEBUG
         Console.WriteLine("DEBUG is defined");
      #else
         Console.WriteLine("DEBUG is not defined");
      #endif
   }
}
Output :

DEBUG is not defined

   

   

7. #warning

코드의 특정위치에서 수준 1의 경고를 생성할 수 있습니다.

   

Example)

// preprocessor_warning.cs
// CS1030 expected
#define DEBUG
public class MyClass 
{
   public static void Main() 
   {
      #if DEBUG
      #warning DEBUG is defined
      #endif
   }
}

8. #error

 코드의 특정 위치에서 오류를 생성할 수 있습니다.

   

Example)

// preprocessor_error.cs
// CS1029 expected
#define DEBUG
public class MyClass 
{
   public static void Main() 
   {
      #if DEBUG
      #error DEBUG is defined
      #endif
   }
}

9. #line

 오류 및 경고에 대해 컴파일러가 출력하는 줄 번호와 파일 이름을 수정할 수 있습니다.

 #line 지시문은 빌드 프로세스의 자동화된 중간 단계에서 사용합니다. 예를 들어, 원본 소스 코드 파일의 줄을 제거했지만 컴파일러에서 파일의 원래 줄 번호를 따라 출력하려는 경우, 줄을 제거한 다음 #line을 사용하여 원래 줄 번호를 시뮬레이션할 수 있습니다.

#line hidden 지시문은 이 지시문 다음에 나오는 줄을 디버거에서 숨깁니다. 따라서 개발자가 코드를 단계별로 실행할 경우 #line hidden과 다음 #line 지시문(이 지시문이 다른 #line hidden 지시문이 아니라고 가정하고) 사이에 있는 모든 줄을 건너 뜁니다. 뿐만 아니라 이 옵션을 사용해 ASP.NET에서 사용자 정의 코드와 시스템 생성 코드를 구별하도록 할 수 있습니다. 현재는 ASP.NET에서 이 기능을 주로 사용하지만 앞으로는 보다 많은 소스 생성기에서 이 기능을 사용하게 될 것입니다.

#line hidden 지시문은 오류 보고에 나타나는 파일 이름이나 줄 번호에는 영향을 주지 않습니다. 따라서 숨겨진 블록에서 오류가 발생하더라도 컴파일러가 현재 파일 이름과 오류를 발생시킨 줄 번호를 보고합니다.

소스 코드 파일에 여러 개의 #line 지시문을 사용할 수 있습니다.

   

   

Example 1.)

// preprocessor_line.cs
public class MyClass2
{
   public static void Main() 
   {
      #line 200
      int i;   // CS0168 on line 200
      #line default
      char c;   // CS0168 on line 9
   }
}
Example1 은 줄 번호와 관련된 두개의 경고를 보고하는 방법을 보여줍니다.

#line 200 지시문은 기본값이 #7인 줄 번호를 강제로 200으로 만듭니다. 다른 줄 #9 는 기본 #line지시문의 결과에 따라 일반적인 시퀀스를 따릅니다.

   

Example 2.)

// preprocessor_linehidden.cs
using System;
class MyClass 
{
   public static void Main() 
   {
      Console.WriteLine("Normal line #1.");   // Set a break point here.
      #line hidden
      Console.WriteLine("Hidden line.");
      #line default
      Console.WriteLine("Normal line #2.");
   }
}

Example 2. 는 디버거가 코드의 숨겨진 줄을 무시하는 방법을 보여줍니다. 실행하면 이상없이 텍스트 세 줄이 표시 됩니다. 그러나 중단점을 걸어놓고 F10 키로 단계적 실행을 수행하면 디버거가 숨겨진 줄을 무시합니다. 뿐만 아니라 숨겨진 줄에 중단점을 설정하더라도 디버거가 해당 줄을 무시합니다.

   

10. #region / #endregion

 제일 많이 사용들 하시는 개요 표시 및 숨기기 기능입니다.

   

Example)

// preprocessor_region.cs
#region MyClass definition
public class MyClass 
{
   public static void Main() 
   {
   }
}
#endregion

'개발 > C#' 카테고리의 다른 글

C#에서 전처리기(#define,#ifdef 등) 사용  (0) 2013.05.12
Microsoft Visual Studio 2010 서비스 팩 1  (0) 2013.05.11
Posted by brent.lee
이전버튼 1 2 이전버튼

태그목록

공지사항

Yesterday
Today
Total
07-15 15:11

달력

 « |  » 2025.7
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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함