조건문

프로그램의 흐름을 제어하기 위한 문법.  조건식이 True 일 경우 수행할 명령문을 코드 블록으로 구성해 기술해야함


if문

어떤 조건을 만족하는 경우, 명령문을 수행하기 위해 사용


if ~ else문

어떤 조건을 만족하는 경우의 명령문과 만족하지 않았을 경우의 명령문을 상호 배타적으로 수행하고자 할 때 사용


if ~ elif ~ else문

2개 이상의 다중 조건을 처리하고자 할 때 사용


제어문 활용




연산자

 연산자

의미 

예 

양변의 값을 더하기

a = 3 + 2 # 5 

양변의 값을 빼기 

a = 3 - 2 # 5

양변의 값을 곱하기

a = 3 * 2 # 6

좌변의 값을 우변의 값으로 나누기 

a = 3/2 # 1.5 

// 

좌변의 값을 우변의 값으로 나눈 몫 

a = 3 // 2 # 1 

좌변의 값을 우변의 값으로 나눈 나머지 

a = 3 % 2 # 1 

**

좌변의 값을 우변의 값으로 제곱 

a = 3 ** 2 # 9 



복합대입연산자


관계연산자

프로그램에서 값을 비교함

산자

의미 

예 

==

양변의 값이 같으면 True 반환 

a, b = 3,2; a == b # False 

!= 

양변의 값이 다르면 True 반환 

a, b = 3,2; a != b # True 

 좌변의 값이 우변의 값보다 크면 True 반환

a, b = 3,2; a > b # True 

좌변의 값이 우변의 값보다 작으면 True 반환 

a, b = 3,2; a < b # False 

>= 

좌변의 값이 우변의 값보다 크거나 같으면 True 반환 

a, b = 3, 2; a >= b # True 

<= 

좌변의 값이 우변의 값보다 작거나 같으면 True 반환 

a, b = 3,2; a <= b # False 



논리연산자

특정 조건을 만족하는지를 검사하기 위함

연산자 

의미 

예 

 and

양변의 값 모두 True일 경우에만 True 반환 

a, b = True, False; a and b # False 

or 

양변의 값 모두 False일 경우에만 False 반환 

a, b = True, False; a or b # True 

not 

True일 경우 False, False 일 경우 True 반환 

a = True; not a # False 



비트연산자

비트 기반의 연산자

 연산자

의미 

예 

양변의 비트 값 모두 1일 경우에만 1를 반환

x, y = 1, 0
x & y # 0 

양변의 값 모두 0일 경우에만 0를 반환 

x, y = 1, 0 

x | y = 1 

^

양변의 값이 다를 경우 1, 같을 경우 0을 반환 

x, y = 1, 0

x ^ y =  1

~

비트 값이 1일 경우 0, 0일 경우 1를 반환

x = 1

~x # -2 

<< 

좌변의 값을 우변의 값 만큼 비트를 왼쪽으로 이동 

x = 4

x << 1 # 8 

>> 

좌변의 값을 우변의 값 만큼 비트를 오른쪽으로 이동 

x = 8

x >> 1 # 4 



# 변수란

값을 저장할 때 사용하는 식별자이고 이며 파이썬은 동적 타이핑 언어로 저장된 값의 자료형에 의해 변수 자료형이 결정된다. 그래서 주의를 필요로하며 type() 함수를 이용하여 자료형을 확인할 수 있다. 


# 변수명

파이썬의 변수는 문자, 숫자, _ 를 조합하여 만들수 있으며 숫자로 시작할 수 없다. 


# 변수와 객체

파이썬의 모든 정보는 객체로 만들어진다. 리터럴로 만들어진 객체는 재사용하여 사용하므로 아래와 같은 예시처럼 True가 출력된다.


# 변수와 자료형

Bool - 참, 거짓을 판단하는 표현식으로 True와 False 값을 가짐


Tuple - () 안에 서로 다른 자료형의 값을 콤마(,)로 구분해 하나 이상 저장할 수 있는 컬렉션 자료형

 0부터 시작하는 인덱스를 이용해 접근할 수 있고 한 번 저장된 항목은 변경할 수 없음

List - [] 안에 서로 다른 자료형의 값을 콤마(,)로 구분해 하나 이상 저장할 수 있는 컬렉션 자료형

0부터 시작하는 인덱스를 이용해 접근할 수 있고 저장된 항목도 변경이 가능함


Set - {} 안에 서로 다른 자료형의 값을 콤마(,)로 구분해 하나 이상 저장할 수 있는 컬렉션 자료형

순서의 개념이 존재하지 않아 인덱스를 사용할 수 없고 데이터 항목의 중복을 허용하지 않음


Dictionary - {} 안에 키:값 형식의 항목을 콤마(,)로 구분해 하나 이상 저장할 수 있는 컬렉션 자료형

키를 이용해 값을 읽어올 수 있으며 항목을 추가할 때 동일키가 없으면 새로운 항목을 추가하고, 동일키가 있으면 저장된 항목을 변경한다.



None - None 객체를 이용해 널(null) 객체 상태를 표현함. 

최초 변수를 선언할 때 초기화를 하지 않으면 에러가 발생함. 초기화 값을 제공하지 않을 경우엔 None 객체 저장 필요

다양한 변수 선언, 초기화 방법




1. 숫자형의 특징

리터럴(Literal)

소스코드 상에서 내장 자료형의 상수 값을 나타내는 용어

type() 함수

파이썬은 값에 의해 자료형이 결정되는 동적 타이핑 언어의 성격을 가지므로 type() 함수를 통해 자료형을 확인한다.

1
2
3
4
5
6
7
8
9
10
>>> type(15)
<class 'int'>
>>> type(3.14)
<class 'float'>
>>> type('파이썬')
<class 'str'>
>>> type(True)
<class 'bool'>
>>> type([123])
<class 'list'>
cs

숫자형

  • 정수형: 정수형의 길이는 무제한이며, 메모리가 허용하는 범위까지 사용할 수 있음. 10진수 뿐만아니라 0o(8진수), 0x(16진수), 0b(2진수) 값도 표현이 가능하다

    1
    2
    3
    4
    5
    6
    7
    8
    >>> 0o177
    127
    >>> 0o377
    255
    >>> 0xdeadbeef
    3735928559
    >>> 0b100110111
    311
    cs
  • 부동소수점형: 큰 수를 표현하기위해 지수표현법도 가능하며 소수점 생략, 지수부 생략도 가능하다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> 3.14
3.14
>>> -2.4
-2.4
>>> 10.
10.0
>>> .001
0.001
>>> 1e100
1e+100
>>> 3.14e-10
3.14e-10
>>> 0e0
0.0
cs
  • 허수형: 3+2j(i와 같음): 파이썬에서 허수는 i대신 j를 사용함. 
1
2
3
4
5
6
7
8
>>> 3.14j
3.14j
>>> 10.j
10j
>>> 10j
10j
>>> 0.001j
0.001j
cs


문자열

문자열이란 문자들의 집합이다. 파이썬에는 문자형은 제공하지 않는다. 


이스케이프 시퀀스

프로그램의 소스 코드 내에서 사용할 수 있도록 백슬래시 기호와 조합해서 사용하는 사전에 정의해둔 문자 조합으로 문자열의 출력 결과를 제어하기 위해 사용함


문자열 포맷팅

문자열을 출력하는데 포맷을 지정하는 방법인데 다른 프로그래밍 언어와 크게 다르지 않다. 오랜만에 정리해보록 하자 ..

유형 

내용 

%s 

문자열 포맷 

%c 

문자 포맷. 정수를 유니코드 문자로 변환해 출력 

%d 

10진 정수 

%o 

8진수 

%x 

16진수 

%f 

부동소수점 숫자로 출력. 

%% 

 %출력



1
2
3
4
5
6
7
8
9
10
>>> "이름: %s" % "홍길동"
'이름: 홍길동'
>>> "나이: %s 세" %20
'나이: 20 세'
>>> "결혼: %s" % False
'결혼: False'
>>> "키: %s cm" %180.5
'키: 180.5 cm'
>>> "이름: %(name)s \n나이: %(age)s세 " % {"name" : "홍길동""age" : 20}
'이름: 홍길동 \n나이: 20세 '
cs


위의 문자열을 이용한 방법은 다른 프로그래밍 언어와 같으니 간단하게 정리하고 넘어가겠다..


str.format() 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> "이름: {0}, 나이: {1} 세".format("홍길동"20)
'이름: 홍길동, 나이: 20 세'
>>> "이름: {}, 나이: {} 세".format("홍길동"20)
'이름: 홍길동, 나이: 20 세'"
>>> "{0:c} => {1}".format(97, 97)
'a => 97'
>>> "{0}, {1}, {2:x}".format('가', ord(""), ord(""))
'가, 44032, ac00'
>>> "{0:f} {1:.2f}".format(3.14, 3.14)
'3.140000 3.14'
>>>  "이름: {name}, 나이: {age} 세".format(name='홍길동', age=20)
'이름: 홍길동, 나이: 20 세'
>>>  "{0:<10}".format("좌측정렬")
'좌측정렬      '
>>>  "{0:^10}".format("중앙정렬")
'   중앙정렬   '
>>> "{0:*^10}".format("중앙정렬")
'***중앙정렬***'
>>> "{0:0.2f}".format(3.141592)
'3.14'
>>> "{0:10.2f}".format(3.141592)
'      3.14'
>>> "{{ {0:.1f} }}".format(98.5)
'{ 98.5 }'
cs


주석

프로그램의 코드 앞에 #을 붙여 작성된 부분으로 인터프리터가 해당 부분을 해석하지 않음


1. 통합 개발 환경(IDE)

코딩을 위한 코드 편집기, 컴파일을 위한 컴파일러(혹은 인터프리터), 디버깅으 ㄹ위한 디버거 등 프로그램 개발에 필요한 도구들이 하나의 프로그램 개발 환경으로 통합되어 개발 생산성을 높이는 소프트웨어 
파이썬에는 파이참, 비쥬얼스튜디오코드, 파이데브 등이 있다.

2. 파이참 개발환경 구성

  1. https://www.jetbrains.com/ 사이트 접속 후 PyCharm 메뉴 클릭



  2. 중앙에 DOWNLOAD 버튼을 클릭후 오픈 소스인 Community 버전 다운로드 실행

  3. next 버튼을 누르다가 아래와 같은 옵션선택 화면이 나온다면 체크 후 남은 설치 진행

  4. 설치된 파일(JetBrains PyCharm Community Edition ...)을 실행하면 아래와 같은 화면이 나오는데
    Do not import settings 를 선택한 후 설치를 완료 후 "Start using Pycharm" 버튼을 눌러 실행한다.



  5. "Create New Project" 버튼을 클릭하고 프로젝트를 생성할 위치를 지정한 후 Create버튼을 클릭하여 프로젝트를 생성


  6. File -> New -> Python File 버튼을 클릭하여 파이썬 파일을 만든 후 아래의 예제를 입력한 후 Run을 눌러 실행을 확인한다.
    저같은 경우는 Run탭에서 Run이 비활성화되어 있어서 에디터창을 우클릭후 실행했습니다. 

03. 파이썬의 코드 작성법

들여쓰기

파이썬 인터프리터에 의해 잘못된 들여쓰기가 검사되지 않으면 치명적인 버그가 발생함. 따라서 개발을 진행하기 이전에 표준을 정해놔야함( 4개의 스페이스로 공백문자를 가지도록 함 - 다른 프로그래밍언어의 블록으로 생각하면 될듯)

주석 

파이썬에서 주석은 #을 이용하지만 #이후 coding 지시자는 특별하게 해석하여 인코딩을 지정할 수 있음 .

1
# coding: utf-8
cs

또는 아래와 같은 방법으로도 인코딩을 지정할 수 있음


1
# -*- coding: utf-8 -*-
cs


세미콜론

기본적으로 구문의 끝에 세미콜론을 사용하진 않지만 하나의 라인에 구문을 구분시켜야 할 때 사용할 수 있음
1
2
3
4
>>> print(0); print(1)
0
1
 
cs

파일과 모듈

하나의 py파일은 하나의 모듈로 인식되며 라이브러리 성격일수도 있고, 진입점(main)을 나타낼 수도 있다. 따라서 if문으로 분기처리를 해야한다.
1
2
if __name__ == "__main__":
    print("Hello World")
cs




1. 파이썬이란

다른 프로그래밍 언어에 비해 빠르게 학습할 수 있고 명령의 수행 결과를 빠르게 확인이 가능하다(인터프리터 방식). 또한 확장 기능을 지원하고 다양한 플랫폼에서 사용이 가능한 프로그래밍 언어이다.


2. 파이썬의 역사와 종류

파이썬의 종류

  1. Cpython - C로 작성된 파이썬(일반적인 파이썬)
  2. IronPython - .Net과 Mono용으로 C#으로 구현
  3. Jython - 자바로 구현된 파이썬, 자바가상머신에서 동작 (자바 클래스, 표준 라이브러리 사용 가능)
  4. PyPy - 파이썬으로 구현


3. 파이썬의 특징

특징

  1. 인터프리팅 방식: 명령의 실행결과를 대화형으로 바로 확인
  2. 동적 타이핑: 실행 시간 값에 의해 자료형 결정
  3. 가비지 컬렉터: 생성된 객체에 대한 메모리 관리는 Garbage Collector 이용
  4. 가독성: 코드블록의 들여쓰기 (문법에서 강제함)
  5. 풍부한 라이브러리: 표준 라이브러리와 통합환경이 배포판과 함께 제공( 정규표현식, 운영체제 시스템 호출, XML, 직렬화, 통신 프로토콜, CSV, DB 접속 등 ..)
  6. 유니코드
  7. 오픈소스: 파이썬 소프트웨어 재단에서 관리
  8. 다양한 프로그래밍 패러다임 지원: 객체지향, 함수형 프로그래밍 지원
  9. 학습 용이성
  10. 내장 스크립트 언어

버전

파이썬 2.0 - GarbageCollector와 유니코드 지원
파이썬 3.0 - 2.x 버전의 파이썬과 하위호환성이 없음, 2.6 버전과 2.7버전에는 일부 호환

유니코드

각 나라별 언어를 모두 표현하기위해 만든 통합코드체계(최대 65,536자를 표현)

유니코드는 각 4자리(각 자리마다 16진수로 표현) 하며 16진수 AA00은 2진수로 표현하면  1010 1010 0000 0000 이다

4. 활용분야

  1. 웹 애플리케이션 개발 분야 : 쟝고(django)와 플라스크(Flask) 를 이용하여 웹 애플리케이션을 생산성있게 개발함
  2. 데이터 수집 분야: 웹 크롤링을 이용하여 데이터를 수집합. ( Beautiful Soup, Scrapy )
  3. 데이터 과학 및 인공지능 분야: Numpy(다차원 배열, 선형대수, 난수 등), pandas(데이터 분석), SciPy(수학, 과학 등에서 사용), scikit-learn(데이터 마이닝과 데이터 분석 도구), TensorFlow(머신러닝 및 딥러닝 프레임워크이며 GPU를 이용한 연산 지원),

5. 개발환경 설치

  1. https://www.python.org/ ▶ Downloads ▶ Windows( 운영체제에 맞게 ) ▶  최신버전 ( Latest Python 3 Release - Python 3.7.4 ) 다운로드
  2. Install launcher for all users, Add Python 3.7 to PATH 체크박스 체크 후 Install Now 클릭

  3. 다운로드 완료 후 Close버튼 클릭
  4. 파이썬 실행 및 출력 확인

 

 


 


0. 스프링이란?

스프링은 애플리케이션 개발에 사용되는 프레임워크이다. 이는 개발을 빠르고 효율적으로 할 수 있도록 바탕이 되는 틀과 곹오 프로그래밍 모델, API 등을 제공해준다.
  • 스프링은 스프링 컨테이너 또는 애플리케이션 컨텍스트라고 불리는 스프링 런타임 엔진을 제공한다. 
  • 스프링 컨테이너는 설정정보를 참고로 해서 애플리케이션을 구성하는 오브젝트를 생성하고 관리한다.
프레임워크는 애플리케이션을 구성하는 오브젝트가 생성되고 동작하는 방식에 대한 틀을 제공해줄 뿐만 아니라 어떻게 프로그래밍해야 하는지 기준도 제시해준다. 이런 틀을 프로그래밍 모델이라고 한다

프로그래밍 모델 

  • Ioc/DI는 오브젝트의 생명주기와 의존관계에 대한 프로그래밍 모델이다
  • 서비스 추상화. 특정 기술과 환경에 에 종속되지 않도록 유연한 추상 계층을 두는 방법을 제공한다
  • AOP. 애플리케이션 코드에 산재해서 나타나는 부가적인 기능을 독립적으로 모듈화하는 프로그래밍 모델이다.


01. 오브젝트와 의존관계

빈이란 ?
  • 디폴트 생성자: 자바빈은 파라미터가 없는 디폴트 생성자를 갖고 있어야 한다. 툴이나 프레임워크에서 리플렉션을 이용해 오브젝트를 생성하기 때문에 필요하다
  • 프로퍼미: 자바빈이 노출하는 이름을 가진 속성을 프로퍼티라고 한다. 프로퍼티는 setter와 getter를 이용해 수정 또는 조회할 수 있다.

애플리케이션의 변화는 끊이지 않는다. 문제는 변화는 대체로 집중된 한 가지 관심에 대해 일어나지만 그에 따른 작업은 한 곳에 집중되지 않는 경우가 많다. 즉 코드의 수정이 여러곳에서 일어나고 이러한 작업에 대한 시간, 검증에 대한 불안감이 있을 수 있다. 이러한 문제를 해결하기 위해서는 분리와 확장을 고려한 설계가 필요하다.

상속을 사용하여 관심사를 분리할 수 있지만 상속을 이용하면 단점이 있다. 일단 자바는 다중 상속을 지원하지 않는데 관심사를 분리해야 하는 대상이 다른 클래스를 상속하고 있을 수 있다. 또한 상속관계는 부모-자식 간의 긴밀한 결합을 허용한다. 서브클래스는 슈퍼클래스의 기능을 직접 사용할 수 있고 슈퍼클래스의 변경이 있을 경우 서브클래스도 함께 수정 또는 개발이 이루어져야 한다.  

개발 폐쇄 원칙은 '클래스나 모듈은 확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다'는 원칙이다. 클래스나 모듈은 확장은 손쉽게 가능하지만 변경에 대한 코드 변경은 있지 않아야 한다는 원칙이다.  개방 폐쇄 원칙은 높은 응집도와 낮은 결합도가 만족되어야 한다. 높은 응집도 라는 것은 변화가 일어날 때 해당 모듈에서 변하는 부분이 크다는 의미이다. 낮은 결합도란 책임과 관심사가 다른 오브젝트 또는 모듈과는 느슨하게 연결된 형태를 유지해야 한다는 것이다. 느슨하다는 것은 특정 클래스에 대한 연결이 아닌 인터페이스로 연결된다는 의미이다. 

전략 패턴은 자신의 기능 맥락(context)에서 필요에 따라 변경이 필요한 알고리즘을 인터페이스를 통해 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔서 사용할 수 있게하는 디자인 패턴이다. 즉 Dao클래스에서(context) DB커넥션을 구하는 알고리즘을 외부로 분리한 뒤 필요에 따라 DB커넥션을 구하는 알고리즘을 변경하며 Dao에서 사용되도록 하는 패턴이다. 

제어관계 역전(Ioc)은 일반적인 프로그램의 흐름과는 다른 개념이다. 일반적인 프로그램은 main 메소드에서 필요한 오브젝트를 생성하고 오브젝트의 메소드를 호출하는 식이다. 즉 main 메소드에서 필요한 오브젝트를 '선택하여 사용'하는 것인데 제어 역전에서는 오브젝트가 자신이 사용할 오브젝트를 스스로 선택하지 않고 생성도하지 않는다. 모든 제어 권한을 자신이 아닌 다른 대상에게 위임하기 때문이다. 스프링이 제어권을 가지고 만들고 관계를 부여하는 오브젝트를 빈(bean)이라고 부른다.

간단한 용어 정리.

  • 빈: 스프링이 Ioc 방식으로 관리하는 오브젝트

  • 빈 팩토리: 스프링의 Ioc를 담당하는 핵심 컨테이너를 가리킴. 빈을 등록하고, 생성하고, 조회하고 반환하고, 그 외에 부갖거인 빈을 관리하는 기능을 담당
  • 애클리케이션 컨텍스트: 빈 팩토리를 확장한 Ioc 컨테이너이다. 기본적인 기능은 빈 팩토리와 동일하지만 스프링이 제공하는 각종 부가 서비스를 추가로 제공한다

  • 설정정보/메타정보: 스프링의 설정정보란 애플리케이션 컨텍스트 또는 빈 팩토리가 Ioc를 적용하기 위해 사용하는 메타정보를 말함

  • 컨테이너 또는 Ioc컨테이너: Ioc 방식으로 빈을 관리하다는 의미에서 빈 팩토리나 애플리케이션 컨텍스트를 컨테이너 또는 Ioc컨테이너라고 한다
  • 스프링 프레임워크: Ioc 컨테이너, 애플리케이션 컨텍스트를 포함해서 스프링이 제공하는 모든 기능을 통틀어 말함.

애플리케이션 컨텍스트는 빈을 싱글톤으로 관리한다. 따라서 빈 내의 인스턴스 변수는 읽기전용이 아니라면 매우매우 위험하다. 스프링은 보통 멀티스레드 환경에서 사용되는데 다양한 사용자가 싱글톤 오브젝트를 사용하여 변경 작업을 했을 때 인스턴스 변수를 사용했을 경우 여러 사용자의 요청이 혼합되어 변경이 될 것이다. 따라서 빈 내에서는 읽기전용일 경우에만 인스턴스 변수로 가지고 그 외에는 파라미터나 로컬변수 리턴값을 이용해야 한다.

의존관계는 두 개의 클래스 또는 모듈이 의존관계에 있다고 말할 떄는 항상 방향성을 부여해줘야 한다. A가 B에 의존하고 있다는 것은 B가 변하면 A에 영향이 있다는 것이다. 반면 B는 A의 변화에 영향을 받지 않는다. 인터페이스에 대해서만 의존관계를 만들어두면 인터페이스 구현 클래스와의 관계는 느슨해지면서 변화에 영향을 덜 받는 상태가 된다. 의존관계 주입은 런타임 시에 사용할 오브젝트(의존 오브젝트)를 클라이언트와 연결해주는 작업을 말한다.

의존관계 주입(DI)의 장점

  • 인터페이스를 통해 결합도가 낮은 코드
  • 확장에는 열려있고(인터페이스를 통한 주입) 변경에는 닫혀 있다.


02. 테스트

스프링의 가장 중요한 가치는 객체지향과 테스트라고 한다. 그렇다면 굳이 테스트를 작성해야 하는 이유가 뭘까? 

  • 웹을 통한 테스트를 한다면 하나의 클래스를 테스트하기 위해 서비스 계층, MVC 프레젠테이션 계층까지 포함한 모든 입출력 기능을 만들어야 한다. 스프링의 테스트를 이용하면 테스트할 데이터도 코드로 작성하고 결과도 바로바로 확인할 수 있다.
  • 큰 단위의 기능에 문제가 생겼을 경우 작은 단위의 테스트가 작성되어 있다면 문제 해결이 쉬워진다. 

테스트를 작성하는데 주의해야 할 점

  • 외부 환경에 영향을 받지 않는 테스트를 작성해야 한다.
  • 테스트 실행 순서에 상관없이 동일한 결과를 반환해야 한다.

TDD란 만들고자 하는 기능의 내용을 담고 있으면서 만들어진 코드를 검증도 해줄 수 있도록 테스트 코드를 먼저 만들고, 테스트를 성공하게 해주는 코드를 작성하는 방식의 개발 방법이다. TDD의 기본 원칙은 "실패한 테스트를 성공시키기 위한 목적이 아닌 코드는 만들지 않는다"는 것이다. 

테스트를 수행하는 데 필요한 정보나 오브젝트를 픽스처라고 한다. 일반적으로 픽스처는 여러 테스트에서 반복저ㅏㄱ으로 사용되기 때문에 @Before 메소드를 이용해서 생성하면 편리하다.

@Before 메소드는 @Test 메소드를 실행하기 전에 실행되며 각 @Test 메소드가 실행될 때마다 매번 실행된다. 그러나 @BeforeClass 스태틱 메소드를 클래스 전체에 걸쳐 단 한번만 실행된다. 하지만 보통 스프링이 직접 제공하는 애플리케이션 컨텍스트 테스트 지원기능을 사용하는 것이 더 편리하다.

1
2
3
4
5
6
7
@RunWith(SpringJUnit4ClassRunner.class// 스프링의 테스트 컨텍스트 프레임워크의 JUnit 확장기능
@ContextConfiguration(locations="/applicationContext.xml"// 테스트 컨텍스트가 자동으로 만들어줄 애플리케이션 컨텍스트의 위치 지정
public class UserDaoTest { 
    // 테스트 오브젝트가 만들어지고 나면 스프링 테스트 컨텍스트에 의해 자동으로 값이 주입됨
    @Autowired
    private ApplicationContext context;
}
cs


03. 템플릿

템플릿은 개방 폐쇄 원칙과 관련이 있다. 이 원칙은 코드에서 어떤 부분은 변경을 통해 그 기능을 다양해지고 확장하려는 성질이 있고, 어떤 부분은 고정되어 있고 변하지 않으려는 성질이 있음을 말해준다. 
템플릿이란 바뀌는 성질이 다른 코드 중에서 변경이 거의 일어나지 않으며 일정한 패턴으로 유지되는 특성을 가진 부분을 자유롭게 변경되는 성질을 가진 부분으로부터 독립시켜서 효과적으로 활용할 수 있도록 하는방법이다.

전략 패턴의 기본 구조에 익명 내부 클래스를 활용한 방식을 스프링에서는 템플릿/콜백 패턴이라고 부른다. 전략 패턴의 컨텍스트를 템플릿이라 부르고, 익명 내부 클래스로 만들어지는 오브젝트를 콜백이라고 부른다. 템플릿에 콜백함수(전략)을 전달하는 것이 DI와 비슷한데 일반적인 DI라면 템플릿에 인스턴스 변수를 만들어두고 사용할 의존 오브젝트를 수정자 메소드로 받아서 사용할 것이다. 반면에 템플릿/콜백 방식에서는 매번 메소드 단위로 사용할 오브젝트를 새롭게 전달받는다는 것이 특징이다. 

04. 예외

런타임 예외 중심의 전략은 낙관적인 예외처리 기법이라고 할 수 있다. 일단 복구할 수 있는 예외는 없다고 가정하고 예외가 생겨도 어차피 런타임 예외이므로 시스템 레벨에서 알아서 처리해 줄 것이고 꼭 필요한 경우는 런탕미 예외라도 잡아서 복구하거나 대응할 수 있다. 반면에 시스템 또는 외부의 예외상황이 원인이 아니라 애플리케이션 자체의 로직에 의해 의도적으로 발생시키고 반드시 catch 해서 무엇인가 조치를 취하도록 요구하는를 애플리케이션 예외라고 한다. 애플리케이션 예외는 체크 예외로 만들어서 예외상황에 대한 로직을 강제로 구현하도록 하는 것이 좋다.  

SQL Exception과 같이 코드레벨에서 대응이 불가능한 예외는 필요도 없는 기계적인 throws 선언이 등장하도록 방치하지 말고 가능한 한 빨리 언체크/런타임 예외로 전환해줘야 한다. 

체크 예외와 언체크 예외를 구분하는 기준은 코드 레벨에서 복구가능한지 여부로 결정하거나 또는 애플리케이션 로직에 영향을 줄 수 있으므로 예외 상황에 대해 강제로 인식이 필요할 때 인듯함

  • 예외를 잡아서 아무런 조취를 취하지 않거나 의미 없는 throws 선언을 남발하는 것은 위험하다
  • 예외는 복구하거나 예외처리 오브젝트로 의도적으로 전달하거나 적절한 예외로 전환해야 한다.
  • 좀 더 의미 있는 예외로 변경하거나, 불필요한 catch/throws를 피하기 위해 런타임 예외로 포장하는 두가지 방법의 예외전환이 있다.
  • 복구할 수 없는 에외는 가능한 한 빨리 런타임 예외로 전환하는 것이 바람직하다.
  • 애플리케이션의 로직을 담기 위한 예외는 체크 예외로 만든다
  • JDBC의 SQL Exception은 대부분 복구할 수 없는 예외이므로 런타임 예외로 포장해야한다.
  • SQL Exception의 에러 코드는 DB에 종속되기 때문에 DB에 독립적인 예외로 전환될 필요가 있다.
  • 스프링은 DataAccessException을 통해 DB에 독립적으로 적용 가능한 추상화된 런타임 예외 계층을 제공한다.
  • DAO를 데이터 엑세스 기술에서 독립시켜려면 인터페이스 도입과 런타임 예외 전환, 기술에 독립적인 추상화된 예외로 전환이 필요하다.

05. 서비스 추상화

  • 비즈니스 로직을 담은 코드는 데이터 엑세스 로직을 담은 코드와 깔끔하게 분리되는 것이 바람직하다. 비즈니스 로직 코드 또한 내부적으로 책임과 역할에 따라서 깔끔하게 메소드로 분리되어야 한다. 
  • 이를 위해서는 DAO의 기술 변화에 서비스 계층의 코드가 영향을 받지 않도록 인터페이스와 DI를 활용해서 결합도를 낮춰야 한다.
  • DAO를 사용하는 비즈니스 로직에는 단위 작업을 보장해주는 트랜잭션이 필요하다
  • 트랜잭션의 시작과 종료를 지정하는 일은 트랜잭션 경계설정이라고 한다. 트랜잭션 경계설정은 주로 비즈니스 로직안에서 일어나는 경우가 많다.
  • 시작된 트랜잭션 정보를 담은 오브젝트를 파라미터로 dao에 전달하는 방법은 매우 비효율적이기 때문에 스프링이 제공하는 트랜잭션 동기화 기법을 활용하는 것이 편리하다.
  • 자바에서 사용되는 트랜잭션 API의 종류와 방법은 다양하다. 환경과 서버에 따라서 트랜잭션 방법이 변경되면 경계설정 코드도 함께 변경돼야 한다.
  • 트랜잭션 방법에 따라 비즈니스 로직을 담은 코드가 함께 변경되면 단일 책임 원칙에 위배되며,  DAO가 사용하는 특정 기술에 대해 강한 결합을 만들어낸다.
  • 트랜잭션 경계설정 코드가 비즈니스 로직 코드에 영향을 주지 않게 하려면 스프링이 제공하는 트랜잭션 서비스 추상화를 이용하면 된다.
  • 서비스 추상화는 로우레벨의 트랜잭션 기술과 api의 변화에 상관없이 일관된 API를 가진 추상화 계층을 도입한다.
  • 서비스 추상화는 테스트하기 어려운 JavaMail 같은 기술에도 적용할 수 있다. 테스트를 편리하게 작성하도록 도와주는 것만으로도 서비스 추상화는 가치가 있다.
  • 테스트 대상이 사용하는 의존 오브젝트를 대체할 수 있도록 만든 오브젝트를 테스트 대역이라고 한다.
  • 테스트 대역은 테스트 대상 오브젝트가 원할하게 동작할 수 있도록 도우면서 테스트를 위해 간접적인 정보를 제공해주기도 한다.
  • 테스트 대역 중에서 테스트 대상으로부터 전달받은 정보를 검증할 수 있도록 설계된 것을 목 오브젝트고 한다.


순열

- n개의 원소를 가지는 배열에서 r개의 원소를 선택하여 나열하는 문제. 여기서는 n == r 로 가정하겠다.


조건


풀이전략

(1) 선택된 원소의 인덱스를 표현하는 selectedIndex배열을 선언.
(2) selectedIndex의 인덱스를 0 ~ n-1까지 증가시키며 인덱스에 위치할 수 있는
    후보군 인덱스 배열을 구한다 (getCandidates)
(3) 선택된 인덱스에 반복문을 이용하여 후보군에서 구한 인덱스를 대입한다 
(4) 백트래킹을 실행한다. (2) ~ (3) 반복


구현하기

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import java.util.ArrayList;
import java.util.List;
 
/**
 * n개의 원소를 가지는 배열의 모든 순열을 구하는 문제
 * @author troh
 *
 */
public class Stack백트래킹_순열 {
    // n개의 원소를 가지는 배열
    private static int[] arr = {1234};
    // 순열의 인덱스를 가리키는 배열
    private static int[] index = {-1-1-1-1};
    
    public static void main(String[] args) {
        backTracking(index, -13);
    }
    
    public static void backTracking(int[] selectedIndex, int k, int input) {
        // 결과 출력
        if(k == input) {
            System.out.printf("{");
            for(int i=0; i<=k; i++) {
                System.out.printf(" %d", arr[selectedIndex[i]]);
            }
            System.out.printf("}\n");
        } else {
            k++;
            /**
             * k인덱스에 대입할 수 있는 인덱스를 구하는 구함
             * 예를 들어 인덱스 0에는 { 0, 1, 2, 3} 
             * 모두 가능하지만 0번째 인덱스에 1을 선택했다면
             * 다음 인덱스 1에는 1을 제외한 {0, 2, 3}이 선택 가능함
             */
            int[] candidates = getCandidates(selectedIndex, k, input);
            for(int i=0; i<candidates.length; i++) {
                selectedIndex[k] = candidates[i];
                backTracking(selectedIndex, k, input);
            }
        }
    }
    
    /**
     * 현재까지 선택되지않은 순열 반환
     * @param a 현재까지 선택된 순열
     * @param k 배열의 최대 인덱스
     * @return
     */
    public static int[] getCandidates(int[] selectedIndex, int k, int input) {
        /**
         * 선택되지 않은 원소찾기
         */
        boolean[] selectedIndexCheck = new boolean[input+1];
        for(int i=0; i<k; i++) {
            selectedIndexCheck[selectedIndex[i]] = true;
        }
        
        /**
         * 선택되지않은 원소의 인덱스를 배열로 만들어서 반환
         */
        int[] nonSelectedIndex = new int[input-k+1];
        int tempIndex = 0;
        for(int i=0; i<input+1; i++) {
            if(selectedIndexCheck[i] == false) {
                nonSelectedIndex[tempIndex] = i;
                tempIndex++;
            }
        }
        return nonSelectedIndex;
    }
}
 
cs


+ Recent posts