2013年10月10日 星期四

[R] OOP(1) class的寫法

OOP就是 object-oriented programming的縮寫

中文比較常見的翻譯是「物件導向」

我其實還蠻討厭把「物件導向」不斷掛在嘴上的人,因為我覺得這四個字非常難以顧名思義

尤有甚者,一大堆屬性啦、方法啦之類完全莫名其妙的名詞就是要嚇退那些剛剛接觸程式設計的人阿!

好啦曾經的我就是被嚇得很慘的人之一(愧)




言歸正傳,說到OOP,R裡語言中當然也是有class寫法的

R語言裡主要有兩種形態的class:S3和S4

S3 Class

在R中最原始的class就是S3 class

我們可以把任何東西指定一個S3 class,比如說一個list開始

假設我今天把a這個list指定給一個叫做BodyIndex的類別
> a<- list(name="John", weight=65, height=166)
> class(a)<- "BodyIndex"
> a
$name
[1] "John"

$weight
[1] 65

$height
[1] 166

attr(,"class")
[1] "BodyIndex"

我們現在就可以幫這個特定的class寫一個他的print
print.BodyIndex<- function(l){
    BMI<- l$weight/((l$height/100)^2)
    cat(l$name,"\n")    
    cat("BMI is ", BMI)
}

當我們再請系統把它print出來的時候
> a
John 
BMI is  23.58833

S3 class當然是可以繼承的
> b<- list(name="Tom", weight=75, height=172, sex="Male")
> class(b)<- c("profile","BodyIndex")
> b
Tom 
BMI is  25.35154

隨著需求,你可以改寫更多某個類別專屬的內建函數(generic function)

S4 Class

R語言裡也提供比較安全的S4類別,但是寫法就比較複雜了

首先要用setClass()定義class

然後用new()把特定的東西指向class
> setClass("BodyIndex",
+     representation(
+         name = "character",
+         weight = "numeric",
+         height = "numeric"
+     )
+ )
> a<- new("BodyIndex",name="John", weight=65, height=166)

在S4 class裡的member我們都叫做slot

我們可以用@把他們叫出來
> a@name
[1] "John"
> a@weight
[1] 65
> a@height
[1] 166

然後不同於S3 class,S4 class是用show()讓我們看到它裡面的slot
> show(a)
An object of class "BodyIndex"
Slot "name":
[1] "John"

Slot "weight":
[1] 65

Slot "height":
[1] 166

當然我們也可以修改它,只是要用setMethod()
> setMethod("show", "BodyIndex",
+     function(obj){
+         BMI<- obj@weight/((obj@height/100)^2)
+         cat(obj@name,"\n")    
+         cat("BMI is ", BMI)
+     }
+ )

> a
John 
BMI is  23.58833

S4 class的架構下可以用setGeneric()設定自己的generic function
> setGeneric("Warnning",
+     function(obj){
+         BMI<- obj@weight/((obj@height/100)^2)
+         if(BMI>35){
+             cat("You are over-weight")
+         }else{cat("You are normal")}
+     } 
+ )

> Warnning(a)
You are normal

當然也可以用setMethod()客制化

> setMethod("Warnning", "BodyIndex",
+     function(obj){
+         BMI<- obj@weight/((obj@height/100)^2)
+         if(BMI>35){
+             cat("You are over-weight")
+         }else{cat("Good for you~~")}
+     } 
+ )

> Warnning(a)
Good for you~~

沒有留言:

張貼留言