编程对象简介
R虽然有S3、S4、(RC)Reference classes 三个面向对象的系统和一个多由C语言构建的基本类型(base types),但是一般S3就能够满足大多数的R编程。因为,在R中我们通常都是为已存在的通用函数(如print()、summary()和plot())创建相当简单的对象和方法,然后在进行调用。由于S3是一个非常随意的系统,没有正式的类定义;加上S4系统与S3相似而且更加正式,因此先了解S4后,再回过头看S3是一个非常取巧的学习方法。
S4对象介绍
S4对象是一种标准的R语言面向对象实现方式,S4对象有明确的类定义,参数定义,参数检查,继承关系,实例化等的面向对象系统的的结构化特征,更适合面向对象的程序设计。
所有的S4相关代码均存在methods包中,S4非常复杂,但是好在有很多权威的资料供我们参考。如:
Software for data analysis: Programming with R - by John Chambers
[Martin Morgan’s answers to S4 questions on stackoverflow](http://stackoverflow.com/search?tab=votes&q=user%3a547331%20%5bs4%5d%20is%
3aanswe)
S4 框架介绍
S4的泛型函数分离了方法的定义和实现,也就是常说的接口和调用分离。即通过S4对象系统,把原来的函数定义和调用2步法,分成了4步进行:
-
定义数据对象类型
-
定义接口类(泛型函数)
-
定义方法类
-
把数据对象以参数传入到泛型函数,调用实现函数
CLASS | 泛型类 | 方法类 |
---|---|---|
setClass():定义 | setGeneric() | setMethod() |
class:类名 | 创建新泛型类或将现有函数转换为泛型类 | 通过联系泛型类、class中的参数,并利用function实现函数调用 |
slots: 属性和类型 | name :泛型类名 | f :泛型类名 |
prototype: 属性的默认值 | def:函数定义 | definition:方法定义 |
contains: 定义父类,继承源头 | signature : the method dispatch signature | signature:class类名 |
validity: 属性的类型检查 | ||
sealed: 同名类是否能被再定义 | ||
new():通过类名和slots中的参数创建对象 |
定义类并创建对象
如上表所示,S4的类(class)可以通过setClass()实现,而new()则可以通过类名和slots中的参数创建跟该类相关的对象。
# 创建Class - Person
setClass("Person", slots = list(name = "character", age = "numeric"))
# 创建Class - Employee,利用contains表明参数继承自Person。
setClass("Employee", slots = list(boss = "Person"), contains = "Person")
# 设置基于Class - Person的对象
alice <- new("Person", name = "Alice", age = 40)
# 设置基于Class - Employee的对象
john <- new("Employee", name = "John", age = 20, boss = alice)
str(alice)
str(john) # 可以看到jhon多了一个slot,即@boss
通过prototype 设置初始值,当创建对象时,如果slots中的属性为空时,该对象会调用初始值作填入。
# 创建Class - Person
setClass("Person", slots = list(name = "character", age = "numeric"), prototype = list(age = 20))
alice <- new("Person", name = "Alice")
str(alice)
通过setValidity设置类属性检查,当通过new()创建对象时,setValidity将对slots 中的参数进行检查、输出报告。
setClass("Person", slots = list(name = "character", age = "numeric"), prototype = list(age = 20))
setValidity("Person",
function(object){
if (object@age < 18)
"he/she is too yong to get the job."
})
new("Person", name = "Penny", age = 17)
如果定义的S4类(class)中包含(继承)了S3类或基础类,该S4类(class)中将有一个包含底层基础类或S3对象的.Data slots:
setClass("RangedNumeric",
slots = list(min = "numeric", max = "numeric"),
contains = "numeric")
rn <- new("RangedNumeric", 1:10, min = 1, max = 10)
str(rn)
构造泛型类和方法类
setGeneric()可以创建或将原有的类转换为泛型类,如果setGeneric()只是将原有的类转换为泛型,那么只需要setGeneric("names")就可以了;如果从头创建一个新的泛型,还需要提供一个名叫standardGeneric()的function,function里面就填泛型类的名字就可以:
setGeneric("myGeneric", function(x) {
standardGeneric("myGeneric")
})
setMethod()利用泛型的名称、与该方法相关联的类以及实现该方法的函数实现参数调用和函数运行。
可以使用getGenerics()获得所有S4泛型的列表;使用getClasses()获得所有S4类的列表;可以使用showMethods()列出所有S4方法。
S4的泛型函数的定义和调用
该代码参考(copy)自R的极客理想中的R语言基于S4的面向对象编程,全文用深入浅出的方式介绍了S4泛型函数。
# 定义几何图形类
setClass("geometric_figure", slots = list(name = "character",
shape = "character"))
# 定义圆形类, 利用prototype定义默认属性参数
setClass("Circle", slots = list(radius="numeric"),
prototype = list(shape = "circle"),
contains = "geometric_figure")
# 定义验证类,保证Circle 类中的属性正常
setValidity("Circle", function(object){
if (object@radius <= 0)
stop("The radius of circle is negative!")
})
# 面积计算 --------------------------------------------------------------------
# 定义计算面积的泛型函数接口
setGeneric("area",function(object){
standardGeneric("area")
})
# 定义面积的计算方法
setMethod("area","Circle",function(object){
cat("The shape of", object@name, "is", object@shape,
"\nThe Area of it is", pi*object@radius^2)
})
# 周长计算 --------------------------------------------------------------------
# 定义计算周长的泛型函数接口
setGeneric("circum",function(object) standardGeneric("circum"))
# 定义计算周长的方法
setMethod("circum","Circle",function(object){
cat("The circumference of", object@name, "is",
2*pi*object@radius)
})
# 创建圆形实例
c <-new("Circle", name="c", radius=5)
# 函数调用 --------------------------------------------------------------------
area(c)
circum(c)
上述过程已经创建了几何图形(geometric_figure)类和面积|周长的泛型函数接口。如果想要计算其他图形,如椭圆、正方形、矩形,三角形、梯形等的周长和面积,只需要通过setClass()定义好继承类,然后再利用setMethod()定义好计算方法,最后就可以通过area()或者circum调用相关函数进行计算,自此就实现了接口和调用分离的S4函数调用全程。
参考资料
除了上面的连接,主要还参考了Advanced R programming - by Hadley Wickham
网友评论