参考:http://cos.name/2009/07/studying-notes-on-oop-in-r/
http://blog.fens.me/r-class-s3/
S3方法
- 在R语言中,基于S3对象的面向对象编程,是一种基于泛型函数的实现方式。泛型函数是一种特殊的函数, 根据传入对象的类型决定调用哪个具体的方法。基于S3对象实现的面向对象编程,不同其他语言的面向对象编程,是一种动态函数调用的模拟实现。
- S3对象被广泛应用于R的早期的开发包中。
对于S3对象的使用,通常用UseMethod()函数来定义一个泛型函数的名称, 通过传入参数的class属性,来确定不同的方法调用。
whoAmI <- function(x,...) UseMethod("whoAmI");
whoAmI.foo <- function(x,...) print("I am a foo");
whoAmI.bar <- function(x,...) print("I am a bar");
whoAmI.default <- function(x) print("I don't konw who I am");
B)S3对象没有明确结构关系,
一个S3对象可以有多个类型, S3对象的 class 属性可以是一个向量,包括多种类型。
一个S3对象可以有多个类型, S3对象的 class 属性可以是一个向量,包括多种类型。
meth1 <- function(x) UseMethod("meth1");
meth1.Mom <- function(x) print("Mom's meth1");
meth1.Dad <- function(x) print("Dad's meth1");
meth2 <- function(x) UseMethod("meth2");
meth2.Dad <- function(x) print("Dad's meth2");
C) 方法调用时,通过传入参数的class属性,来确定不同的方法调用。
例如: x <- structure(1,"Mom"); 那么meth1(x)将执行meth1.Mom行为。
a) 可以通过methods()函数来查看S3对象中定义的内部行为函数。
如: methods(meth1);
b) 可以通过methods()的generic.function参数,来匹配泛函名字。
如:methods(generic.function=predict);
c) 可以通过methods()的class参数,来匹配类的名字。
如:methods(class=lm);
d) 用用getAnywhere()函数,查找所有的函数(包含隐藏函数,
如predict.ppr)。
D)利用S3
简单地模拟继承关系
由于S3参数的class属性有多个值时,调用时只会会按照程序赋值顺序来调用第一个合法的函数。
为了能够模拟继承关系,
就只有使用NextMethod()函数来实现且同时定义该对象多个class属性。
如,
node <- function(x) UseMethod("node",x);node.default <- function(x) "Default node";
node.father <- function(x) c("father");
node.son <- function(x) c("son",NextMethod()); # Nextmethod
n1 <- structure(1,class=c("father"));
node(n1);
# 必须设置class属性为两个
n2 <- structure(1,class=c("son","father"));
# 在node函数中传入n2,执行node.son()函数和node.father()函数
node(n2);
E)S3方法的优缺点
- S3使用起来简单,但在实际的面向对象编程过程中,当对象关系有一定的复杂度,S3对象所表达的意义就会变得不太清楚。
- S3封装的内部函数,可绕过泛型函数的检查,以直接被调用。(有时候也不是缺点)
- S3参数的class属性,可以被任意设置,没有预处理的检查。
- S3参数,只能通过调用class属性进行函数调用,其他属性则不会被class()函数执行。
- S3参数的class属性有多个值时,调用时只会按照程序赋值顺序来调用第一个合法的函数,除非有NextMethod()函数。