17.3 참조(reference) 클래스

이 절에서는 세 가지 클래스 시스템 중 하나인 R 프로그래밍에서 참조(reference) 클래스로 작업하는 방법을 학습하겠습니다.

R 프로그래밍의 참조 클래스는 C ++, Java, Python 등과 같은 공통 언어에서 사용되는 개체 지향 프로그래밍과 유사합니다. 참조 클래스에서는 S3S4 클래스와 달리 메소드는 일반 함수가 아닌 클래스에 속합니다. 참조 클래스는 환경이 추가된 S4 클래스로 내부적으로 구현됩니다.

17.3.1 참조 클래스를 정의하는 방법

참조 클래스를 정의하는 것은 S4 클래스를 정의하는 것과 유사합니다. 다만, setClass() 대신에 setRefClass() 함수를 사용하는 것입니다.

setRefClass("student")

클래스의 멤버 변수가 정의된 경우 클래스 정의에 포함되어야 합니다. 참조 클래스의 멤버 변수필드라고합니다 (S4 클래스의 슬롯과 유사함).

다음은 이름(name), 나이(age) 그리고 GPA의 3 개 필드가 있는 st라는 클래스를 정의하는 예입니다.

setRefClass("st", fields = list(name = "character", age = "numeric", GPA = "numeric"))

17.3.2 참조 개체를 만드는 방법

setRefClass() 함수는 해당 클래스의 개체를 생성하는 데 사용되는 생성 함수를 반환합니다.

st <- setRefClass("st", fields = list(name = "character", age = "numeric", GPA = "numeric"))

# 이제 student() 함수는 새로운 개체를 생성하는 데 사용될 수 있는 생성 함수입니다.
ref.s <- st(name = "John", age = 21, GPA = 3.5)
ref.s
## Reference class object of class "st"
## Field "name":
## [1] "John"
## Field "age":
## [1] 21
## Field "GPA":
## [1] 3.5

17.3.3 필드에 액세스하고 수정하는 방법

$ 연산자를 사용하여 개체의 필드에 액세스할 수 있습니다.

ref.s$name
## [1] "John"
ref.s$age
## [1] 21
ref.s$GPA
## [1] 3.5

마찬가지로 재할당을 통해 수정됩니다.

ref.s$name <- "Paul"
ref.s
## Reference class object of class "st"
## Field "name":
## [1] "Paul"
## Field "age":
## [1] 21
## Field "GPA":
## [1] 3.5

17.3.3.1 경고 참고

R 프로그래밍에서 개체는 새 변수에 할당되거나 (값으로) 함수에 전달될 때 복사됩니다. 예를 들면.

# 리스트 a를 생성하고 b에 할당합니다.
a <- list("x" = 1, "y" = 2)
b <- a

# b를 수정합니다.
b$y = 3

# a에게는 아무런 영향이 미치지 않습니다.
a
## $x
## [1] 1
## 
## $y
## [1] 2
# b만 수정됩니다.
b
## $x
## [1] 1
## 
## $y
## [1] 3

그러나 참조 객체의 경우가 이렇지 않습니다. 단지 사본만이 존재하고 모든 변수가 동일한 사본을 참조합니다. 따라서 다음의 내용을 확인해 보겠습니다.

# 참조 개체 a를 생성하고, b에 할당합니다.
a <- st(name = "John", age = 21, GPA = 3.5)
b <- a

# b를 수정합니다.
b$name <- "Paul"

# 그러면 a와 b 모두 수정됩니다.
a
## Reference class object of class "st"
## Field "name":
## [1] "Paul"
## Field "age":
## [1] 21
## Field "GPA":
## [1] 3.5
b
## Reference class object of class "st"
## Field "name":
## [1] "Paul"
## Field "age":
## [1] 21
## Field "GPA":
## [1] 3.5

이로 인해 원치 않는 값의 변경이 발생할 수 있으며, 이상한 버그의 원인이 될 수 있습니다. 참조 개체로 작업하는 동안 이를 염두에 두어야 합니다. 복사본을 만들기 위해, copy() 메소드를 사용할 수 있습니다.

# 참조 개체 a를 생성하고, a의 copy를 b에 할당합니다.
a <- st(name = "John", age = 21, GPA = 3.5)
b <- a$copy()

# b를 수정합니다.
b$name <- "Paul"

# a는 아무런 영향이 없습니다.
a
## Reference class object of class "st"
## Field "name":
## [1] "John"
## Field "age":
## [1] 21
## Field "GPA":
## [1] 3.5
# b만 수정됩니다.
b
## Reference class object of class "st"
## Field "name":
## [1] "Paul"
## Field "age":
## [1] 21
## Field "GPA":
## [1] 3.5

17.3.4 참조 메소드

메소드는 참조 클래스에 대해 정의되며, S3S4 클래스에서 처럼 일반 함수에는 속하지 않습니다.

모든 참조 클래스는 사전에 정의된 메소드를 가지고 있습니다. 이 메소들은 수퍼 클래스 envRefClass에서 상속되기 때문입니다.

st
## Generator for class "st":
## 
## Class fields:
##                                     
## Name:       name       age       GPA
## Class: character   numeric   numeric
## 
## Class Methods: 
##      "field", "trace", "getRefClass", "initFields", "copy", "callSuper", 
##      ".objectPackage", "export", "untrace", "getClass", "show", "usingMethods", 
##      ".objectParent", "import"
## 
## Reference Superclasses: 
##      "envRefClass"

위 목록에서 copy(), field() 그리고 show()와 같은 클래스 메소드를 볼 수 있습니다. 이 클래스에 대한 자체 메소드도 만들 수 있습니다.

이것은 함수 정의 목록을 setRefClass()의 메소드 인수에 전달하여 클래스 정의 중에 수행할 수 있습니다.

st <- setRefClass("st", fields = list(name = "character", age = "numeric", GPA = "numeric"),
                methods = list(
                             inc_age = function(x) {
                                          age <<- age + x
                                       },
                             dec_age = function(x) {
                                          age <<- age - x
                                       }
                              )
                )

위의 코드 섹션에서 inc_age()dec_age/ ()라는 두 가지 메소드를 정의했습니다. 이 두 가지 메소드는 age 필드를 수정합니다.

age가 메소드의 로컬 환경에 없기 때문에 로컬이 아닌 할당 연산자 <<-를 사용해야 합니다. 이것은 중요합니다. 간단한 할당 연산자 <-를 사용하면 우리가 원하는 것이 아닌 age라는 지역 변수가 생성되었을 것입니다. 이러한 경우 R은 경고를 발하게 됩니다.

다음은 위에 정의된 메소드를 사용하는 실행의 예를 보겠습니다.

ref.s3 <- st(name = "John", age = 21, GPA = 3.5)
ref.s3$inc_age(5)
ref.s3$age
## [1] 26
ref.s3$dec_age(10)
ref.s3$age
## [1] 16

참고 자료 : https://www.datamentor.io/r-programming/reference-class/