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")

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

你可能感兴趣的:(R语言,r)