7.1 S3方法
S3方法和白色的书一致.
在R的观念中,一个对象的属性可以是一组异常丰富的数据对象.在面向对象系统中,S3方法以clsss属性为驱动.它是一个可选的系统.只有当一个对象拥有class属性时,S3方法才会真正起到作用.
有一些函数是泛型的.例如print(),plot(),summary().这些函数查询第一个入参是否带有class属性.如果第一个入参拥有一个class属性,那么这个泛型函数就会搜寻一个它拥有的能够匹配该class属性的具体函数.如果匹配成功,这个具体函数就会被调用.如果不存在该class类型的具体函数,那么默认函数会被调用.
我们来个具体的.函数lm()(线性模型)返回一个”lm”类型的对象.关于此方法的输出函数有print.lm()和print.default().lm()调用的输出由print.lm()来输出.1:10的结果输出则由print.default()完成.
S3方法简单而强大.对象被恰当地输出,绘图和汇总,用户不用关心.用户只需要知道print(),plot()和summary()就好了.
对于免费的午餐也会有一点开销.print()是泛型的意味着你的所见并非所得(有时是这样的).对于一个对象的输出,你或许想要看到一个你想要的数字–比如说一个”R-squared”–但是你并不知道怎样去获得这个数字.如果你的神秘数字在obj,那么你有一些方法去查找:
print.default(obj)
print(unclass(obj))
str(obj)
前两个假设对象没有class,最后一个输出对象的结构.你也可以这样:
names(obj)
来查看这个对象包含的元素–这个可以提供给你对象的概观.
7.1.1 泛型函数
有时一个新的使用者对median()会有一点点好奇并且想知道它是这么工作的.然后情理之中,他会敲击函数名称去看看:
> median
function (x, na.rm = FALSE)
UseMethod("median")
<environment: namespace:stats>
这个新的使用者就又问了,”怎样我才能看到median()的函数代码呢?”
答案是,”你已经看到它的代码了.”又UseMethod()的出现可以证明median()是一个泛型函数.这个新用户想问的是,”我怎样才能找到median()的默认方法?”
最确切的方法是使用getS3method():
getS3method(’median’, ’default’)
7.1.2 方法
methods()列举一个泛型函数的方法.可替代地如果输入一个class,methods()就会列举那些对此class提供方法的泛型函数.这个陈述需要一些限制:
- 它会列举当前对话所依附的方法.
- 它以名字为索引-它将列举generic.class类型的对象.这是合理的聪明的,但是这也会愚蠢地列举那些并不是真正的方法的对象.
median(当前对话情况下)的所有方法可以这样获得:
methods(median)
“factor”类的方法可以这样获得:
methods(class=’factor’)
7.1.3 继承
类可以继承自其它类.例如:
> class(ordered(c(90, 90, 100, 110, 110)))
[1] "ordered" "factor"
“ordered”类继承自”factor”类.Ordered因素是因素,但是不是所有的因素是ordered类.如果”ordered”有一个明确的泛型方法,那么当函数调用第一个入参是是”ordered”类,这个方法将会被调用.然而,如果这里没有关于”ordered”类的此类方法,但是有关于”factor”类的此类的方法,那么”factor”类的方法会被调用.
继承应该基于对象结构上的相似性,而不是对象概念上的相似性.矩阵和数据框拥有相似的概念.矩阵是数据框的一个特例(所有列拥有相同的类型),因此在概念上继承是有意义的.然而矩阵和数据框有完全不同的实现方法,因此继承并没有实际意义.继承的作用是拥有重复使用代码的能力.