큐 모듈 작성하기
앞 절에서 작성한 큐 코드의 작성자는 큐의 맨 뒤에 데이터를 저장하고 큐의 맨 앞에서 데이터를 가져오도록 설계했다. 하지만 q라는 변수가 전역으로 선언되어 있으므로 이 함수를 거치지 않고 외부에서 데이터를 조작해버릴 수 있다. 그리고 이때 데이터의 무결성Integrity이 다음과 같이 깨질 수 있다.
> enqueue(1) > q <- c(q, 5) # 전역 변수 q를 조작 > print(size()) [1] 1 > dequeue() [1] 1 > dequeue() [1] 5 > size() [1] -1
보다시피 q의 외부에서 q에 직접 값을 할당해버린 탓에 실제로는 q 내부에 데이터가 2개 저장되어 있지만 size( )를 호출했을 때 크기가 1로 나타나는 문제가 있다. 이러한 문제를 막기 위한 방법은 큐 코드 전체와 관련된 변수를 한 함수 안으로 감추는 것이다.
> queue <- function() { + q <- c() + q_size <- 0 + + enqueue <- function(data) { + q <<- c(q, data) + q_size <<- q_size + 1 + } + + dequeue <- function() { + first <- q[1] + q <<- q[-1] + q_size <<- q_size - 1 + return(first) + } + + size <- function() { + return(q_size) + } + + return(list(enqueue=enqueue, dequeue=dequeue, size=size)) + }
이 코드가 앞서와 다른 점이라면 q와 q_size가 이제 queue( ) 함수 안에 있는 지역 변수라는 점이다. 따라서 이 변수들은 외부에서 접근이 불가능하다. 또 함수 enqueue( ), dequeue( ), size( )는 함수 queue( )의 반환 값이 되었고 이 값은 리스트로 반환되고 있다.
이렇게 만든 queue( )는 다음과 같이 사용할 수 있다.
> q <- queue() > q$enqueue(1) > q$enqueue(3) > q$size() [1] 2 > q$dequeue() [1] 1 > q$dequeue() [1] 3 > q$size() [1] 0
queue( ) 함수 호출 시 만들어지는 queue( ) 함수 내부의 지역 변수 q와 q_size가 생성되는 공간은 queue( ) 함수를 호출할 때마다 매번 새로 생성된다. 즉, queue( )를 다음과 같이 여러 개 만들어서 사용해도 데이터가 서로 섞이지 않게 된다.
> q <- queue() > r <- queue() > q$enqueue(1) > r$size() [1] 0 > r$enqueue(3) > q$dequeue() [1] 1 > r$dequeue() [1] 3 > q$size() [1] 0 > r$size() [1] 0
이러한 코딩 기법을 모듈 패턴이라고 하며, <Software for Data Analysis>[4]에 소개되어 있다. 그러나 모듈 패턴은 비단 R만의 전유물은 아니며, 자바스크립트에서도 같은 이름으로 널리 사용되어 <JavaScript Module Pattern: In-Depth>[5] 등의 문서에 소개되어 있다.