R是一个基于使用泛型函数的面向对象的编辑语言。每个对象有一个类属性,这个类属性决定当对象的副本传递到类似于print(), plot()和summary()这些泛型函数时运行函数时运行什么代码。  

     R有两个分离的面向对象编程的模型。S3模型相对更老、更简单、结构更少。S4模型更新且单探讨S3模型的局限性和S4模型如何试图解决这些问题。

泛型函数

     R使用对象的类来确定当一个泛型函数被调用时采取的行动。考虑下面的代码:

summary(women)

     height         weight     
 Min.   :58.0   Min.   :115.0  
 1st Qu.:61.5   1st Qu.:124.5  
 Median :65.0   Median :135.0  
 Mean   :65.0   Mean   :136.7  
 3rd Qu.:68.5   3rd Qu.:148.0  
 Max.   :72.0   Max.   :164.0  

fit <- lm(weight ~ height, data=women)
summary(fit)

Call:
lm(formula = weight ~ height, data = women)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.7333 -1.1333 -0.3833  0.7417  3.1167 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -87.51667    5.93694  -14.74 1.71e-09 ***
height        3.45000    0.09114   37.85 1.09e-14 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.525 on 13 degrees of freedom
Multiple R-squared:  0.991,     Adjusted R-squared:  0.9903 
F-statistic:  1433 on 1 and 13 DF,  p-value: 1.091e-14

第一个代码summary()函数对women数据框中的每个变量都进行了描述性分析。在第二个summary()函数对该数据框的线性回归进行了描述。这是如何发生的呢?

让我们来看看summary()函数的代码:

summary
function (object, ...) UseMethod("summary")

我们看看women数据框和fit对象的类:

class(women)
[1] "data.frame"
> class(fit)
[1] "lm"

如果函数summary.data.frame(women)存在,summary(women)函数执行summary.data.frame(women),否则执行summary.default(women).

同样,如果summary.lm(fit)存在,summary(fit)函数执行summary.lm(fit),否则执行summary.defalut(fir).

UseMethod()函数将对象分派给一个泛型函数,前提是该泛型函数有扩展与对象的类匹配。

为了列出可获得的S3泛型函数,可以使用methods()函数:

> methods(summary)
 [1] summary.aov                   
 [2] summary.aovlist*              
 [3] summary.aspell*               
 [4] summary.check_packages_in_dir*
 [5] summary.connection            
 [6] summary.data.frame            
 [7] summary.Date                  
 [8] summary.default               
 [9] summary.ecdf*                 
[10] summary.factor                
[11] summary.glm                   
[12] summary.infl*                 
[13] summary.lm                    
[14] summary.loess*                
[15] summary.manova                
[16] summary.matrix                
[17] summary.mlm*                  
[18] summary.nls*                  
[19] summary.packageStatus*        
[20] summary.POSIXct               
[21] summary.POSIXlt               
[22] summary.ppr*                  
[23] summary.prcomp*               
[24] summary.princomp*             
[25] summary.proc_time             
[26] summary.srcfile               
[27] summary.srcref                
[28] summary.stepfun               
[29] summary.stl*                  
[30] summary.table                 
[31] summary.tukeysmooth*          
[32] summary.warnings

返回的函数个数取决于机器安装的包的个数。在我的电脑上独立的summary()函数已经定义了32类。可以使用getAnywhere()函数查看代码,如getAnywhere(summary.glm)。

下面的代码清单定义了名为mymethod()的泛型函数。

#1.定义泛型函数
mymethod <- function(x, ...) UseMethod("mymethod")
 mymethod.a <- function(x) print("Using A")
 mymethod.b <- function(x) print("Using B")
 mymethod.default <- function(x) print("Using Default")
#2.给对象分配类
 x <- 1:5
 y <- 6:10
 z <- 10:15
 class(x) <- "a"
 class(y) <- "b"
#3.把泛型函数应用到对象中
 mymethod(x)
[1] "Using A"
 mymethod(y)
[1] "Using B"
 mymethod(z)
[1] "Using Default"
#4.把泛型函数应用到包含两个类的对象中
 class(z) <- c("a", "b")
 mymethod(z)
[1] "Using A"
 class(z) <- c("b", "a")
 mymethod(z)
[1] "Using B"

#5.泛型函数没有默认为"c"的类
 class(z) <- c("c","a", "b")
 mymethod(z)
[1] "Using A"

一个对象可以被分配到一个以上的类,在这种情况下R如何决定使用哪个泛型函数呢?如4中对象z被分配到两类时,第一类用来决定哪个泛型函数被调用。在5中没有mymethod.c()函数,因此一下个类a被使用。

R从左到右搜索类的列表,寻找一个可用的泛型函数。