1) 세로를 가로의 데이터로 만들기
/* Formatted on 2010/10/07 14:11 (Formatter Plus v4.8.8) */
WITH tmp AS
(SELECT '1' AS col1, 'A' AS col2
FROM DUAL
UNION ALL
SELECT '2' AS col1, '가' AS col2
FROM DUAL
UNION ALL
SELECT '1' AS col1, 'B' AS col2
FROM DUAL
UNION ALL
SELECT '1' AS col1, 'C' AS col2
FROM DUAL)
SELECT col1, LTRIM (SYS_CONNECT_BY_PATH (col2, ','), ',') AS col1
FROM (SELECT col1, col2,
ROW_NUMBER () OVER (PARTITION BY col1 ORDER BY col1) rn,
COUNT (*) OVER (PARTITION BY col1) cnt
FROM tmp)
WHERE LEVEL = cnt
START WITH rn = 1
CONNECT BY PRIOR col1 = col1 AND PRIOR rn = rn - 1;
2) 세로를 가로의 컬럼 데이터로 만들기
/* Formatted on 2010/10/07 16:07 (Formatter Plus v4.8.8) */
WITH tmp AS
(SELECT '1' AS col1, 'a' AS col2
FROM DUAL
UNION ALL
SELECT '2' AS col1, '가' AS col2
FROM DUAL
UNION ALL
SELECT '1' AS col1, 'b' AS col2
FROM DUAL
UNION ALL
SELECT '1' AS col1, 'c' AS col2
FROM DUAL)
SELECT col1, MIN (DECODE (r, 1, col2)), MIN (DECODE (r, 2, col2)),
MIN (DECODE (r, 2, col2))
FROM (SELECT col1, col2,
ROW_NUMBER () OVER (PARTITION BY col1 ORDER BY col2) r
FROM tmp)
GROUP BY col1
/* Formatted on 2010/10/07 14:11 (Formatter Plus v4.8.8) */
WITH tmp AS
(SELECT '1' AS col1, 'A' AS col2
FROM DUAL
UNION ALL
SELECT '2' AS col1, '가' AS col2
FROM DUAL
UNION ALL
SELECT '1' AS col1, 'B' AS col2
FROM DUAL
UNION ALL
SELECT '1' AS col1, 'C' AS col2
FROM DUAL)
SELECT col1, LTRIM (SYS_CONNECT_BY_PATH (col2, ','), ',') AS col1
FROM (SELECT col1, col2,
ROW_NUMBER () OVER (PARTITION BY col1 ORDER BY col1) rn,
COUNT (*) OVER (PARTITION BY col1) cnt
FROM tmp)
WHERE LEVEL = cnt
START WITH rn = 1
CONNECT BY PRIOR col1 = col1 AND PRIOR rn = rn - 1;
2) 세로를 가로의 컬럼 데이터로 만들기
/* Formatted on 2010/10/07 16:07 (Formatter Plus v4.8.8) */
WITH tmp AS
(SELECT '1' AS col1, 'a' AS col2
FROM DUAL
UNION ALL
SELECT '2' AS col1, '가' AS col2
FROM DUAL
UNION ALL
SELECT '1' AS col1, 'b' AS col2
FROM DUAL
UNION ALL
SELECT '1' AS col1, 'c' AS col2
FROM DUAL)
SELECT col1, MIN (DECODE (r, 1, col2)), MIN (DECODE (r, 2, col2)),
MIN (DECODE (r, 2, col2))
FROM (SELECT col1, col2,
ROW_NUMBER () OVER (PARTITION BY col1 ORDER BY col2) r
FROM tmp)
GROUP BY col1
Textus Ciceronis
3.2.3 SUM(DECODE…) 사용시 주의사항
- 편리한 나머지 남용하는 사례가 늘고 있다;
- 편리한 나머지 남용하는 사례가 늘고 있다;
- 오남용 사례와 치료요법
가. NULL값의 처리
- 예의 널 공포증 문제
- 함부로 NVL함수를(특히 행 단위 처리 내에서) 사용하면 비효율이 발생한다.
- NULL 값은 애초에 비교 대상에서 제외되므로, NULL인 행을 선택하는 DECODE가 아니면 NVL을 사용할 필요가 없다.
- SUM(DECODE…) 연산에서는 NULL은 아예 연산에서 제외되므로 굳이 NVL(col, 0)을 사용할 필요가 없다. (NVL을 DECODE 안에 사용하면 쓸데없는 연산이 발생한다.)
- SUM(DECODE…)에서 DECODE로 추출된 행 전체의 값이 NULL이어서 결과가 NULL인 경우, 0으로 표시해주고 싶다면, SUM 바깥에 NVL을 사용해주면 된다.
- 두 개 이상의 열의 연산에 대한 SUM이 필요한 경우
: DECODE문 안에 NVL을 안 쓰면 한 열만 NULL인 행도 연산에서 제외되는 문제 발생
à 각 열의 SUM에 대한 연산으로 전개하면 굳이 NVL을 사용하지 않아도 된다.
- ELSE 부의 값이 0인 경우 SUM에서는 NULL인 경우와 결과가 달라지지 않으므로 굳이 ELSE부를 쓸 이유가 없다. (ELSE부 값이 없으면 NULL처리되므로 수행속도의 차이 발생)
가. NULL값의 처리
- 예의 널 공포증 문제
- 함부로 NVL함수를(특히 행 단위 처리 내에서) 사용하면 비효율이 발생한다.
- NULL 값은 애초에 비교 대상에서 제외되므로, NULL인 행을 선택하는 DECODE가 아니면 NVL을 사용할 필요가 없다.
- SUM(DECODE…) 연산에서는 NULL은 아예 연산에서 제외되므로 굳이 NVL(col, 0)을 사용할 필요가 없다. (NVL을 DECODE 안에 사용하면 쓸데없는 연산이 발생한다.)
- SUM(DECODE…)에서 DECODE로 추출된 행 전체의 값이 NULL이어서 결과가 NULL인 경우, 0으로 표시해주고 싶다면, SUM 바깥에 NVL을 사용해주면 된다.
- 두 개 이상의 열의 연산에 대한 SUM이 필요한 경우
: DECODE문 안에 NVL을 안 쓰면 한 열만 NULL인 행도 연산에서 제외되는 문제 발생
à 각 열의 SUM에 대한 연산으로 전개하면 굳이 NVL을 사용하지 않아도 된다.
- ELSE 부의 값이 0인 경우 SUM에서는 NULL인 경우와 결과가 달라지지 않으므로 굳이 ELSE부를 쓸 이유가 없다. (ELSE부 값이 없으면 NULL처리되므로 수행속도의 차이 발생)
나. 반복 DECODE의 감소
- SUM(DECODE…)에서 가장 부하가 큰 부분은 DECODE 콤보; 부분이다.
- 특히 nested decode는 매우 부하가 크다.
- 수행속도를 위해 DECODE를 단순하게 만들어 줄 필요가 있다.
- 수행속도 절감 사례;
- 여러 열에 대해 계속 다중 DECODE를 쓰는 경우
: 각 열을 하나로 concatnation해서 DECODE하면 하나의 DECODE로 줄일 수 있다. (DECODE 안은 좀 길어지지만;)
- 범위 처리(a : SUM(DECODE(SIGN(b-x), 1, DECODE(SIGN(a-x), -1, y)))
à SUM(DECODE(ABS(a-x)+ABS(b-x), b-a, y))
- 열 조합에 의한 경우의 수가 매우 많은 경우
: 2진분류나 10진분류등 기수법 체계를 활용한다.
- 여러가지 수학함수를 이용해서 최대한 간단한 수학적 모델을 만들어낸다.
- SUM(DECODE…)에서 가장 부하가 큰 부분은 DECODE 콤보; 부분이다.
- 특히 nested decode는 매우 부하가 크다.
- 수행속도를 위해 DECODE를 단순하게 만들어 줄 필요가 있다.
- 수행속도 절감 사례;
- 여러 열에 대해 계속 다중 DECODE를 쓰는 경우
: 각 열을 하나로 concatnation해서 DECODE하면 하나의 DECODE로 줄일 수 있다. (DECODE 안은 좀 길어지지만;)
- 범위 처리(a : SUM(DECODE(SIGN(b-x), 1, DECODE(SIGN(a-x), -1, y)))
à SUM(DECODE(ABS(a-x)+ABS(b-x), b-a, y))
- 열 조합에 의한 경우의 수가 매우 많은 경우
: 2진분류나 10진분류등 기수법 체계를 활용한다.
- 여러가지 수학함수를 이용해서 최대한 간단한 수학적 모델을 만들어낸다.
다. SUM(DECODE…)와 GROUP BY 비교
- SUM(DECODE…)를 이용해 추출할 열이 많은 경우의 부하를 줄이기 위해 GROUP BY를 사용할 수 있다.
SUM(DECODE(공통수식, 경우1, 값1)), SUM(DECODE(공통수식, 경우2, 값2)), SUM(DECODE(공통수식, 경우3, 값3)), ……
à SUM(DECODE(A, 경우1, 값1)), SUM(DECODE(A, 경우2, 값2)), SUM(DECODE(A, 경우3, 값3)), …... FROM (SELECT 공통수식 A, …… GROUP BY 공통수식)
è 결과값은 뒤의 SQL이 좀더 보기 흉해-_-지지만 수행속도는 훨씬 빠르다.
(GROUP BY를 한 번더 사용하는 성형수술은 부하가 크지 않다.)
- SUM(DECODE…)를 이용해 추출할 열이 많은 경우의 부하를 줄이기 위해 GROUP BY를 사용할 수 있다.
- SUM(DECODE…)를 이용해 추출할 열이 많은 경우의 부하를 줄이기 위해 GROUP BY를 사용할 수 있다.
SUM(DECODE(공통수식, 경우1, 값1)), SUM(DECODE(공통수식, 경우2, 값2)), SUM(DECODE(공통수식, 경우3, 값3)), ……
à SUM(DECODE(A, 경우1, 값1)), SUM(DECODE(A, 경우2, 값2)), SUM(DECODE(A, 경우3, 값3)), …... FROM (SELECT 공통수식 A, …… GROUP BY 공통수식)
è 결과값은 뒤의 SQL이 좀더 보기 흉해-_-지지만 수행속도는 훨씬 빠르다.
(GROUP BY를 한 번더 사용하는 성형수술은 부하가 크지 않다.)
- SUM(DECODE…)를 이용해 추출할 열이 많은 경우의 부하를 줄이기 위해 GROUP BY를 사용할 수 있다.
라. COUNT(DECODE…)의 활용
- 개수만 알아내는 데에는 SUM보다 COUNT가 수행속도면에서 훨씬 유리하다. (근데 대체 개수 알아내는데 SUM을 왜 쓰냐? -_-)
- COUNT(특정 열) 보다 COUNT(*)이 더 빠르다.
- *는 ‘모든 열’이 아니라 ‘조건을 만족하는 열에 대한 wild card’의 의미를 가진다.
- 개수만 알아내는 데에는 SUM보다 COUNT가 수행속도면에서 훨씬 유리하다. (근데 대체 개수 알아내는데 SUM을 왜 쓰냐? -_-)
- COUNT(특정 열) 보다 COUNT(*)이 더 빠르다.
- *는 ‘모든 열’이 아니라 ‘조건을 만족하는 열에 대한 wild card’의 의미를 가진다.
마. GROUP BY 문에서 MIN의 활용
- 일관성을 지키지 않은 못된-_- 테이블을 처리해야 하는 경우, GROUP BY 연산에서 해당 열이 NULL인 행과 NULL이 아닌 행에 대해 각각 새로운 행이 생성되는 경우가 있다.
à MIN을 이용해 해결한다.
- SUM, AVG등은 숫자에만 가능하지만, MIN, MAX등은 모든 형태에 다 사용 가능하다.
- 일관성을 지키지 않은 못된-_- 테이블을 처리해야 하는 경우, GROUP BY 연산에서 해당 열이 NULL인 행과 NULL이 아닌 행에 대해 각각 새로운 행이 생성되는 경우가 있다.
à MIN을 이용해 해결한다.
- SUM, AVG등은 숫자에만 가능하지만, MIN, MAX등은 모든 형태에 다 사용 가능하다.
바. SQL을 어떻게 공부할 것인가?
- 뻔한 얘기;
- 뻔한 얘기;
3.3. UPDATE문의 활용
3.3.1. 확장 UPDATE문
- DECODE와 같이 조건 처리를 할 수 없는 DBMS에서는 효용이 적다.
- UPDATE에서 가장 중요한 것은 UPDATE할 대상 집합의 명확화이다.
- UPDATE 구문에서는 WHERE절이 선택하는 집합의 크기가 UPDATE의 작업량을 결정하므로 잘 관리해야 한다.
- WHERE절에 있는 서브쿼리가 먼저 수행되면, 결과물이 상수의 집합이 되므로 WHERE절의 처리 범위를 줄일 수 있다.
- 행을 FETCH해서 가공, 처리, 다시 UPDATE하는 절차적 PL/SQL 프로그래밍 루틴을, UPDATE와 SELECT를 이용해서 하나의 SQL로 만들 수 있다.
- 프로그램 루틴의 SQL화 작업 시 주의점
1. SQL이 매우 커지므로 큰 롤백 세그먼트가 필요하며, 롤백이나 커밋시에 매우 많은 행 이 수정되므로 다른 작업에 영향을 줄 수가 있다.
2. 처리 시에 발생하는 개별 행의 에러를 선별하기가 곤란하다.
3. 하나의 SELECT 가공 결과로 여러 테이블을 UPDATE할 수 없다.
4. 서브쿼리에 조건을 만족하는 값이 하나도 없어 선택된 행이 없는 경우, NULL이 업데 이트 될 수 있다. à 가장 critical한 문제점
è EXISTS루틴 등으로 해결
- Error와 Fail의 차이점 : Error는 SQL이 수행되지 않았을 때, Fail은 수행되었으나 결 과가 공집합일 때 발생한다.
- GROUP함수에서 SQL은 절대 실패하지 않는다. (최소 하나의 행이 생성된다.)
è 실패한 SQL에서는 NVL을 사용해도 NULL 값의 발생을 막을 수 없지만, GROUP 함수와 같이 실패하지 않은 SQL에서는 NVL을 사용해 NULL값을 가공할 수 있다.
5. UPDATE문은 항상 UPDATE되는 테이블이 선행해야 하고, SET 절 내의 서브쿼리는 항상 나중에 반복수행되므로, 서브쿼리에서 가공을 위해 추출해야 하는 행이 많을 때에 는 다중처리 방법을 이용해야 한다.
3.3.1. 확장 UPDATE문
- DECODE와 같이 조건 처리를 할 수 없는 DBMS에서는 효용이 적다.
- UPDATE에서 가장 중요한 것은 UPDATE할 대상 집합의 명확화이다.
- UPDATE 구문에서는 WHERE절이 선택하는 집합의 크기가 UPDATE의 작업량을 결정하므로 잘 관리해야 한다.
- WHERE절에 있는 서브쿼리가 먼저 수행되면, 결과물이 상수의 집합이 되므로 WHERE절의 처리 범위를 줄일 수 있다.
- 행을 FETCH해서 가공, 처리, 다시 UPDATE하는 절차적 PL/SQL 프로그래밍 루틴을, UPDATE와 SELECT를 이용해서 하나의 SQL로 만들 수 있다.
- 프로그램 루틴의 SQL화 작업 시 주의점
1. SQL이 매우 커지므로 큰 롤백 세그먼트가 필요하며, 롤백이나 커밋시에 매우 많은 행 이 수정되므로 다른 작업에 영향을 줄 수가 있다.
2. 처리 시에 발생하는 개별 행의 에러를 선별하기가 곤란하다.
3. 하나의 SELECT 가공 결과로 여러 테이블을 UPDATE할 수 없다.
4. 서브쿼리에 조건을 만족하는 값이 하나도 없어 선택된 행이 없는 경우, NULL이 업데 이트 될 수 있다. à 가장 critical한 문제점
è EXISTS루틴 등으로 해결
- Error와 Fail의 차이점 : Error는 SQL이 수행되지 않았을 때, Fail은 수행되었으나 결 과가 공집합일 때 발생한다.
- GROUP함수에서 SQL은 절대 실패하지 않는다. (최소 하나의 행이 생성된다.)
è 실패한 SQL에서는 NVL을 사용해도 NULL 값의 발생을 막을 수 없지만, GROUP 함수와 같이 실패하지 않은 SQL에서는 NVL을 사용해 NULL값을 가공할 수 있다.
5. UPDATE문은 항상 UPDATE되는 테이블이 선행해야 하고, SET 절 내의 서브쿼리는 항상 나중에 반복수행되므로, 서브쿼리에서 가공을 위해 추출해야 하는 행이 많을 때에 는 다중처리 방법을 이용해야 한다.
3.3.2. 수정가능 조인 뷰
- 오라클 7.3 이상부터 적용
- 과거에 비해 비교적 자유롭게 조인 뷰에서 INSERT, DELETE, UPDATE를 할 수 있다. (그래도 여전히 제약이 많다.)
- 오라클 7.3 이상부터 적용
- 과거에 비해 비교적 자유롭게 조인 뷰에서 INSERT, DELETE, UPDATE를 할 수 있다. (그래도 여전히 제약이 많다.)
가. 수정가능 조인뷰의 제한사항
- 오라클 7.3부터 FROM절에 하나 이상의 테이블이나 뷰가 위치하는 조인이 된 뷰를 수정할 수 있게 됨
- 제약조건 : DISTINCT, 그룹함수(SUM, AVG등), 집합처리(UNION, INTERSECT등), GROUP BY와 HAVING처리, ROWNUM의 사용, 순환처리(CONNECT BY/START WITH 구문)을 사용한 뷰는 수정할 수 없다.
- 최종 뷰로 병합 가능한 뷰만 수정할 수 있다.
- 조인된 테이블 중에서 키보존 테이블만 수정할 수 있다.
- 오라클 7.3부터 FROM절에 하나 이상의 테이블이나 뷰가 위치하는 조인이 된 뷰를 수정할 수 있게 됨
- 제약조건 : DISTINCT, 그룹함수(SUM, AVG등), 집합처리(UNION, INTERSECT등), GROUP BY와 HAVING처리, ROWNUM의 사용, 순환처리(CONNECT BY/START WITH 구문)을 사용한 뷰는 수정할 수 없다.
- 최종 뷰로 병합 가능한 뷰만 수정할 수 있다.
- 조인된 테이블 중에서 키보존 테이블만 수정할 수 있다.
나. 키보존 테이블이란?
- 조인으로 인해 변화가 일어난 집합의 논리적인 기본키가 자신의 기본키대로 유지되는 테이블 (조인을 했어도 자기 집합의 키 레벨은 변하지 않는 테이블)
- 1:M 조인의 경우 - 조인 결과의 키는 M측 테이블의 키 레벨이 되므로, M측 테이블은 키 레벨이 변하지 않지만, 1측 테이블은 조인 집합을 식별하는 기본키가 될 수 없다.
- M:M 조인의 경우 – 조인 결과는 둘의 Cartesian Product 만큼의 행이 생성 되므로, 두 테이블 모두 키보존 테이블이 될 수 없다. (M:M은 구현 단계에서 나와서는 안되는 구조이므로 별 걱정할 필요 없다-_-)
- 1:1 조인의 경우 – 조인 결과가 양쪽 테이블의 키 레벨과 같으므로, 두 테이블 모두 키보존 테이블이 될 수 있다.
- 키 레벨이 변경되지 않았어도 OUTER JOIN에 의해 생성된 집합에서는 최하위 테이블이 키보존 테이블이 될 수 없는 경우가 있다. (M측 테이블이 OUTER JOIN되는 경우 NULL 필드들이 양산되므로 더 이상 기본키의 역할을 할 수 없다.)
- 조인으로 인해 변화가 일어난 집합의 논리적인 기본키가 자신의 기본키대로 유지되는 테이블 (조인을 했어도 자기 집합의 키 레벨은 변하지 않는 테이블)
- 1:M 조인의 경우 - 조인 결과의 키는 M측 테이블의 키 레벨이 되므로, M측 테이블은 키 레벨이 변하지 않지만, 1측 테이블은 조인 집합을 식별하는 기본키가 될 수 없다.
- M:M 조인의 경우 – 조인 결과는 둘의 Cartesian Product 만큼의 행이 생성 되므로, 두 테이블 모두 키보존 테이블이 될 수 없다. (M:M은 구현 단계에서 나와서는 안되는 구조이므로 별 걱정할 필요 없다-_-)
- 1:1 조인의 경우 – 조인 결과가 양쪽 테이블의 키 레벨과 같으므로, 두 테이블 모두 키보존 테이블이 될 수 있다.
- 키 레벨이 변경되지 않았어도 OUTER JOIN에 의해 생성된 집합에서는 최하위 테이블이 키보존 테이블이 될 수 없는 경우가 있다. (M측 테이블이 OUTER JOIN되는 경우 NULL 필드들이 양산되므로 더 이상 기본키의 역할을 할 수 없다.)
- 진정한-_- 키보존 테이블이 되기 위해서는 위 조건 말고도, 조인의 연결고리 중에서 조인되는 상대 집합의 연결고리에 반드시 Unique Index가 있어야 한다. (PK 지정으로 자동생성된 Unique Index여도 상관없다.)
- 조인뷰의 UPDATE에서 WHERE절에는 아무거나 올 수 있지만, SET 절에는 키보존 테이블의 열만 올 수 있다.
- 조인뷰의 DELETE에서는 반드시 단 하나의 키보존 테이블만 가져야 한다.
- 조인뷰의 INSERT는 DELETE와 같이 하나의 키보존 테이블만 가져야 가능하며, 여기에 덧붙여 원 테이블의 제약조건(constraints)을 만족해야 한다. (당연한 얘기;)
- 조인뷰의 UPDATE에서 WHERE절에는 아무거나 올 수 있지만, SET 절에는 키보존 테이블의 열만 올 수 있다.
- 조인뷰의 DELETE에서는 반드시 단 하나의 키보존 테이블만 가져야 한다.
- 조인뷰의 INSERT는 DELETE와 같이 하나의 키보존 테이블만 가져야 가능하며, 여기에 덧붙여 원 테이블의 제약조건(constraints)을 만족해야 한다. (당연한 얘기;)
다. 수정가능 조인뷰의 활용
출처 : http://ohgyun.com/279
문서를 정리하다가 예전에 헤드퍼스트 디자인 패턴 책을 읽고 정리해 놓은 파일이 있어 옮겨봅니다.
==============================================================
디자인 원칙
- 애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분으로부터 분리한다.
- 구현이 아닌 인터페이스에 맞춰서 프로그래밍한다.
- 상속보다는 구성을 활용한다.
- 서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결한하는 디자인을 사용해야 한다.
- 클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다.
(OCP : Open-Closed Principle)
- 추상화된 것에 의존하도록 만들어라. 구상클래스에 의존하도록 만들지 않도록 한다.
- 최소 지식 원칙 - 정말 친한 친구하고만 얘기하라.
(다음 네 종류의 객체의 메서드만 호출한다.
1. 객체 자체 / 2. 메서드에 매개변수로 전달된 객체 / 3. 그 메서드에서 생성하거나 인스턴스를 만든 객체 / 4. 그 객체에 속하는 구성 요소)
- 헐리우드 원칙 - 먼저 연락하지 마세요. 저희가 연락 드리겠습니다.
- 클래스를 바꾸는 이유는 한 가지 뿐이어야 한다.
+ ... 나중에 어떻게 바뀔 것인가?
스트래티지 패턴(Strategy Pattern)
- 알고리즘군을 정의하고 각각을 캐슐화하여 교환해서 사용할 수 있도록 만든다.
- 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경할 수 있다.
- 구성을 사용한다.
- 일반적으로 서브클래스를 만드는 방법을 대신하여 유연성을 극대화하기 위한 용도로 쓰인다.
- 예: QuarkBehavior & FlyBehavior
옵저버 패턴(Observer Pattern)
- 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고
자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의한다.
- 주제(Subject) & 옵저버(Observer)
- Observable & Observer:
Observable 에 register, remove, notify 가 있고,
Observer 에 update 가 있다. (notify 에서 update 를 호출)
- 예: 신문 구독 서비스, 기상관측 시스템
데코레이터 패턴(Decorator Pattern)
- 객체에 추가적인 요건을 동적으로 첨가한다.
- 데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.
- 예: 스타버즈 커피
팩토리 패턴(Factory Pattern)
- 팩토리 메서드 패턴 :
객체를 생성하기 위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하게 만든다.
클래스의 인스턴스를 만드는 일을 서브클래스에 맡긴다.
- 제품을 생산하는 부분과 사용하는 부분을 분리시킬 수 있다.
- 추상 팩토리 패턴 :
인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고 생성한다.
구상 클래스는 서브 클래스에 의해 만들어진다.
싱글턴 패턴(Singleton Pattern)
- 해당 클래스의 인스턴스가 하나만 만들어지고,
어디서든지 그 인스턴스에 접근할 수 있도록(전역 접근) 하기 위한 패턴
커맨드 패턴(Command Pattern)
- 요구 사항을 객체로 캡슐화 할 수 잇으며, 매개변수를 써서 여러 가지 다른 요구 사항을 집어넣을 수 있다.
또한 요청 내역을 큐에 저장하거나 로그로 기록할 수도 잇으며, 작업취소 기능도 지원 가능하다.
- 예: 리모콘
- 서블릿의 doGet(), doPost() 또는 스트럿츠의 Action() 메서드도 커맨드 패턴이지 않을까?
어댑터 패턴(Adapter Pattern)
- 한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환한다.
어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.
퍼사드 패턴(Facade Pattern)
- 어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공한다.
퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있다.
- 서브시스템의 호출을 퍼사드에서 처리해준다. (기본 명령 호출 정도랄까...)
- 일련의 클래스들에 대한 인터페이스를 단순화 시킨다.
- 각 패턴별 차이점:
데코레이터 패턴 : 인터페이스는 바꾸지 않고 책임(기능)만 추가
어댑터 패턴 : 한 인터페이스를 다른 인터페이스로 변환
퍼사드 패턴 : 인터페이스를 간단하게 바꿈
템플릿 메서드 패턴(Template Method Pattern)
- 메서드에서 알고리즘의 골격을 정의한다.
알고리즘의 여러 단계 중 일부는 서브클래스에서 구현할 수 있다.
템플릿 메서드를 이용하면 알고리즘의 구조는 그대로 유지하면서 서브클래스에서 특정 단계를 재정의할 수 있다.
- 스트래티지 패턴과 다른 점:
템플릿 메서드 패턴은 알고리즘의 개요를 정의한다. 실제 작업 중 일부는 서브클래스에서 처리.
스트래티지 패턴은 객체 구성을 통해서 알고리즘을 캡슐화 및 구현
- 예) Arrays.sort(배열); --- compareTo() 를 구현하도록 되어 있다.
Applet , init(), start(), stop(), destory()
그렇다면 서블릿에도 템플릿 메서드가 쓰이는 거구나. init() - service() - destory()
이터레이터 패턴(Iterator Pattern)
- 컬렉션 구현 방법을 노출시키지 않으면서도
그 잡합체 안에 들어있는 모든 항목에 접근할 수 있게 해주는 방법을 제공한다.
- 컬렉션의 구현을 드러내지 않으면서 컬렉셔네 있는 모든 객체들에 대해 반복작업할 수 있다.
컴포지트 패턴(Composite Pattern)
- 객체들을 트리 구조로 구성하여 부분과 전체를 나타내는 계층구조로 만들 수 있다.
이 패턴을 이용하면 클라이언트에서 개별 객체와 다른 객체들로 구성된
복합 객체(composite)를 똑같은 방법으로 다룰 수 있다.
- 클라이언트에서 객체 컬렉션과 개별 객체를 똑같은 식으로 처리할 수 있다.
- 예) 트리 구조의 패턴, 디렉토리 구조
- 예) XMLObject 객체가 컴포지트 패턴을 구현한 게 아닐까
스테이트 패턴(State Pattern)
- 객체의 내부 상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있다.
마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있다.
- 상태 전환의 흐름을 결정하는 코드를 어느 쪽에 집어넣는지 잘 고려해야 한다.
(상태 객체인지, Context 객체인지)
- 각 상태를 클래스로 캡슐화함으로써 나중에 변경시켜야 하는 내용을 국지화시킬 수 있다.
- 스트래티지 패턴:
어떤 클래스의 인스턴스를 만들고 그 인스턴스에게 어떤 행동을 구현하는 전략 객체를 건내준다.
스테이트 패턴:
컨텍스트 객체를 생성할 때 초기 상태를 지정해주는 경우 이후로는 컨텍스트 객체가 알아서 상태를 변경.
프록시 패턴(Proxy Pattern)
- 어떤 객체에 대한 접근을 제어하기 위한 용도로 대리인이나 대변인에 해당하는 객체를 제공하는 패턴
- 다른 객체를 대변한느 객체를 만들어서 주 객체에 대한 접근을 제어할 수 있다.
- 원격프록시(remote proxy): 원격 객체에 대한 접근 제어
클라이언트와 원격 객체 사이에서 데이터 전달을 관리
가상프록시(virtual proxy): 생성하기 힘든(인스턴스를 만드는 데 많은 비용이 드는) 자원에 대한 접근 제어
보호프록시(protection proxy): 접근 권한이 필요한 자원에 대한 접근 제어
호출하는 쪽의 권한에 따라서 객체에 있는 메소드에 대한 접근 제어
방화벽 프록시: 일련의 네트워크 자원에 대한 접근 제어
스마트 레퍼런스 프록시: 주 객체가 참조될 때마나 추가 행동을 제공. 객체에 대한 레퍼런스 개수를 세는 등
캐싱 프록시: 비용이 많이 드는 작업의 결과를 임시로 저장
웹 서버 프록시 또는 컨텐츠 관리 및 퍼블리싱 시스템 등에서 사용
동기화 프록시: 여러 스레드에서 주 객체에 접근하는 경우 안전하게 작업을 처리할 목적(분산 환경 등에서 사용)
복잡도 숨김 프록시: 복잡한 클래스들의 집합에 대한 접근을 제어하고 복잡도를 숨겨줌
퍼사드 프록시라고도 함.
프록시에서는 접근을 제어하지만 퍼사드 패턴에서는 대체 인터페이스만 제공
지연 복사 프록시: 클라이언트에서 필요로 할 때까지 객체가 복사되는 것을 지연시킴으로써 객체의 복사 제어
- 아래 객체들은 모두 클라이언트와 객체 사이에 끼여들어서 요청을 전달한다.
데코레이터 패턴: 클래스에 새로운 행동을 추가하기 위한 용도
어댑터 패턴: 다른 객체의 인터페이스를 바꿔주기 위한 용도
프록시 패턴: 어떤 클래스에 대한 접근을 제어하기 위한 용도
- java.reflect.Proxy 에 기능이 내장되어 있다.
디자인 패턴 정의
- 패턴이란 특정 컨텍스트 내에서 주어진 문제에 대한 해결책이다.
- 어떤 컨텍스트 내에서 일련의 제약조건에 의해 영향을 받을 수 있는 문제에 봉착했다면,
그 제약조건 내에서 목적을 달성하기 위한 해결책을 찾아낼 수 있는 디자인을 적용하면 된다.
주의점 및 추가 사항
- 디자인 패턴의 과다한 사용은 불필요하게 복잡한 코드를 초래할 수 있다.
항상 가장 간단한 해결책으로 목적을 달성할 수 있도록 하고, 반드시 필요할 때만 디자인 패턴을 적용하자.
- 코딩할 때 어떤 패턴을 사용하고 있는지 주석으로 적어주자.
클래스와 메서드 이름을 만들 때도 사용 중인 패턴이 분명하게 드러날 수 있도록 해보자.
다른 개발자들이 그 코드를 볼 때 무엇을 어떻게 구현했는지 훨씬 빠르게 이해할 수 있다.
그 외 잘 정리된 참고 사이트 : http://vincehuston.org/dp/