0
点赞
收藏
分享

微信扫一扫

R开发(part11)--基于S4的面向对象编程

学习笔记,仅供参考,有错必纠

参考自:《R的极客理想》-- 张丹


文章目录

  • ​​R开发​​
  • ​​基于S4的面向对象编程​​
  • ​​创建S4对象​​
  • ​​访问S4对象的属性​​
  • ​​S4的泛型函数​​
  • ​​查看S4对象的函数​​


R开发



基于S4的面向对象编程



S4对象系统是一种R语言面向对象实现方式,S4对象有明确的类定义、参数定义、参数检查、继承关系、实例化、接口函数、实现函数等面向对象系统的特征。



创建S4对象



  • setClass函数


S4对象系统有专门的类定义函数setClass和类的实例化函数new,我们先看看setClass的语法。



setClass语法:

setClass(Class, representation, prototype, contains=character(),
validity, access, where, version, sealed, package,
S3methods = FALSE, slots)



setClass参数表:

参数

含义

Class

定义类名

slots

定义属性和属性类型

prototype

定义属性的默认值

contains=character()

定义父类,继承关系

validity

定义属性的类型检查

where

定义存储空间

sealed

如果设置TRUE,则同名类不能被再次定义

package

定义所属的包


  • 创建一个S4对象实例


通过setClass函数定义类的结构,再通过new函数来实例化类对象:

#定义一个S4对象
setClass("Person", slots = list(name = "character", age = "numeric"))

#实例化一个Person对象
father <- new("Person", name = "F", age = 50)
father
#输出start
An object of class "Person"
Slot "name":
[1] "F"

Slot "age":
[1] 50
#输出end

class(father)
#输出start
[1] "Person"
attr(,"package")
[1] ".GlobalEnv"
#输出end

otype(father) #"S4"



  • 创建一个有继承关系的S4对象


如果需要创建有继承关系的S4对象,可以通过setClass函数的contains属性来设置父类:

#定义一个S4对象Person
setClass("Person", slots = list(name = "character", age = "numeric"))

#定义一个S4对象Son, 继承Person
setClass("Son", slots = list(father = "Person", mother = "Person"),
contains = "Person")

#实例化一个Person对象
father <- new("Person", name = "F", age = 50)
mother <- new("Person", name = "M", age = 51)

#实例化一个Son对象
son <- new("Son", name = "S", age = 22,
father = father, mother = mother)

son@name #"S"
son@age #22
son@father
#输出start
An object of class "Person"
Slot "name":
[1] "F"

Slot "age":
[1] 50
#输出end

#查看son对象的mother属性
slot(son, "mother")
#输出start
An object of class "Person"
Slot "name":
[1] "M"

Slot "age":
[1] 51
#输出end

# 检查son类型
otype(son) #"S4"
# 用isS4()检查S4对象的类型
isS4(son) #TRUE
#检查son@mother属性类型
otype(son@mother) #"S4"



  • S4对象的默认值


通过setClass函数的prototype属性给属性字段中定义的参数设置默认值:

#定义一个S4对象Bunny
setClass("Bunny", slots = list(name = "character", age = "numeric"),
prototype = list(age = 20))

b <- new("Bunny", name = "Huang")
b
#输出start
An object of class "Bunny"
Slot "name":
[1] "Huang"

Slot "age":
[1] 20
#输出end



  • S4对象的类型检查


通过setValidity函数给属性字段中定义的参数设置类型检查:

#定义一个S4对象Person
setClass("Person", slots = list(name = "character", age = "numeric"))

setValidity("Person", function(object) {
if (object@age <= 0 | object@age >= 100) {
stop("年龄非法")
}
})

p <- new("Person", name = "T", age = -1)
#报错start
Error in validityMethod(object) : 年龄非法
#报错end



  • 从一个已实例化的对象中创建新对象


S4对象还支持从一个已实例化的对象中创建新对象,创建时可以覆盖对象的值:

# 创建一个对象实例n1
n1 <- new("Person", name="n1", age=19)
# 从实例n1中创建实例n2,并修改name的属性值
n2<-initialize(n1, name="n2")

n1
#输出start
An object of class "Person"
Slot "name":
[1] "n1"

Slot "age":
[1] 19
#输出end

n2
#输出start
An object of class "Person"
Slot "name":
[1] "n2"

Slot "age":
[1] 19
#输出end



访问S4对象的属性



在S3对象中,一般我使用​​$​​​来访问一个对象的属性。但在S4对象中,我们只能使用​​@​​来访问一个对象的属性。

#定义一个S4对象
setClass("Person", slots = list(name = "character", age = "numeric"))

#实例化一个Person对象
father <- new("Person", name = "F", age = 50)
#访问S4对象的属性
father@name #"F"
slot(father, "name") #"F"



S4的泛型函数



S4的泛型函数实现有别于S3的实现,S4分离了方法的定义实现,如在其他语言中我们常说的接口和实现分离。通过setGeneric来定义接口,通过setMethod来定义实现函数。



普通函数的定义和调用:

work <- function(x) cat(x, "is working")
work("Huang") #Huang is working

S4的泛型函数:

#定义一个Person类
setClass("Person", slots = list(name = "character", age = "numeric"))
#定义泛型函数work,即接口
setGeneric("work", function(object) standardGeneric("work"))
#定义work的实现函数,并指定参数类型为Person类的对象
setMethod("work", signature(object = "Person"),
function(object) cat(object@name, "is working"))

p <- new("Person", name = "p1", age = 18)
work(p) #p1 is working

通过S4对象系统,把原来的函数定义及调用过程从2步变成4步:

  • 定义S4类;
  • 定义接口函数;
  • 定义实现函数;
  • 把对象以参数传入接口函数,执行实现函数。


查看S4对象的函数



当我们使用S4对象进行面向对象封装后,我们还需要能查看S4对象的定义和函数定义.

R>#检查work的类型
R>ftype(work)
[1] "s4" "generic"
R>#直接查看work函数
R>work
standardGeneric for "work" defined from package ".GlobalEnv"

function (object)
standardGeneric("work")
<environment: 0x0000000012708a68>
Methods may be defined for arguments: object
Use showMethods("work") for currently available ones.
R>#查看work函数的现实定义
R>showMethods(work)
Function: work (package .GlobalEnv)
object="Person"

R>#查看Person对象的work函数现实
R>getMethod("work", "Person")
Method Definition:

function (object)
cat(object@name, "is working")

Signatures:
object
target "Person"
defined "Person"
R>#检查Person对象有没有work函数
R>existsMethod("work", "Person")
[1] TRUE

举报

相关推荐

0 条评论