2017-08-02 20:37:35
| 方面 | 面向过程 (以事件过程为中心) | 面向对象 (以对象为中心) |
|---|---|---|
特点 |
|
|
优点 |
|
|
缺点 |
|
|
举例 |
|
|
汽车高内聚,低耦合。High cohesion and low couping.
函数(对象, 参数列表)
summary, plot)根据对象的类,自动调用适用的方法对象.方法(参数列表)pryr::otype和pryr::ftype判定对象/函数属于哪个OO系统在S3中,创建和初始化可以同时完成
library(pryr) car1 <- structure(list(manuf="VW", color="white", brand="Golf"), class="Car") otype(car1)
## [1] "S3"
str(car1)
## List of 3 ## $ manuf: chr "VW" ## $ color: chr "white" ## $ brand: chr "Golf" ## - attr(*, "class")= chr "Car"
或
car1 <- list(manuf="VW", color="white", brand="Golf") class(car1) <- "Car"
car2 <- structure(list(manuf="VW", color="red", brand="Audi"),
class=c("Auto", "Car"))
car3 <- structure(list(manuf="VW", color="black", brand="Santana"),
class=c("Manual", "Car"))
bike1 <- structure(list(manuf="Yongjiu", color="yellow", brand="ofo"), class="Bike")
## 是否属于Car类?
sapply(list(car2, car3, bike1), inherits, what="Car")
## [1] TRUE TRUE FALSE
## 泛型函数shiftGear,采取"shiftGear"方法
shiftGear <- function(x, from, to, ...) {
## 校验数据结构
stopifnot(all(c("manuf", "color", "brand") %in% names(x)))
## 调用shiftGear方法
UseMethod("shiftGear")
}
ftype(shiftGear)
## [1] "s3" "generic"
shiftGear.Manual <- function(x, from, to, ...) {
if (from == to) { ## 针对Manual类对象,定义专用的shiftGear方法
print(paste(class(x)[1], "类: 不需要换档"))
}else{
print(paste(class(x)[1], "类:", x$color, x$manuf, x$brand,
"踩离合,再从", from, "档隔级换到", to))
}
}
shiftGear.Car <- function(x, from, to, ...) { ## Car类的通用shiftGear方法
paste("我不知道怎么给", class(x)[1], "类", x$color, x$manuf, x$brand, "换档")
}
shiftGear.default <- function(x, ...) paste(class(x)[1], "类: 无法换档") ## 默认的shiftGear方法
methods(shiftGear)
## [1] shiftGear.Car shiftGear.default shiftGear.Manual ## see '?methods' for accessing help and source code
shiftGear(car2, 2, 4)
## [1] "我不知道怎么给 Auto 类 red VW Audi 换档"
shiftGear(car3, 2, 2)
## [1] "Manual 类: 不需要换档"
shiftGear(car3, 5, 2)
## [1] "Manual 类: black VW Santana 踩离合,再从 5 档隔级换到 2"
shiftGear(bike1, 1, 2)
## [1] "Bike 类: 无法换档"
notACar <- list(manuf="Nobody", color="opaque", brand="Nobrand")
class(notACar) <- c("NotACar", class(car2))
shiftGear(notACar)
## [1] "我不知道怎么给 NotACar 类 opaque Nobody Nobrand 换档"
magrittr::%>%x %>% f(y) ## 等价于 f(x, y)
library(magrittr) car3 %>% shiftGear(4, 2)
## [1] "Manual 类: black VW Santana 踩离合,再从 4 档隔级换到 2"
将方法定义在类内部 (建议用RC)
move <- function(car, speed, ...) UseMethod("move")
move.Car <- function(car, speed, ...)
print(paste(car$color, car$manuf, car$brand, "时速", speed, "行驶"))
car4 <- structure(list(manuf="Toyota", color="white", brand="Accord",
move=function(speed, ...) move(car4, speed, ...)),
class=c("Auto", "Car"))
car4$move(40)
## [1] "white Toyota Accord 时速 40 行驶"
计算右表图形的面积
部分计算公式重温如下:
| shape | edge | neighbor | angle | |
|---|---|---|---|---|
| 1 | 三角形 | 10 | 20 | 45 |
| 2 | 平行四边形 | 10 | 20 | 60 |
| 3 | 矩形 | 10 | 20 | NA |
| 4 | 菱形 | 10 | NA | 45 |
| 5 | 正方形 | 10 | NA | NA |
| 6 | 等边三角形 | 10 | NA | NA |
areas <- c(with(shapes[1,], edge * neighbor * sin(pi*angle/180) / 2),
with(shapes[2,], edge * neighbor * sin(pi*angle/180)),
with(shapes[3,], edge * neighbor),
with(shapes[4,], edge ^ 2 * sin(pi*angle/180)),
with(shapes[5,], edge ^ 2),
with(shapes[6,], edge ^ 2 * sin(pi*60/180)) / 2)
areas
## [1] 70.71068 173.20508 200.00000 70.71068 100.00000 43.30127
toNum <- function(shape, ...){
shape$neighbor <- as.numeric(shape$neighbor)
shape$edge <- as.numeric(shape$edge)
shape$angle <- as.numeric(shape$angle)
return(shape)
}
calcArea <- function(shape, ...) UseMethod("calcArea") ## 泛型函数
calcArea.Triangle <- function(shape, ...) ## 三角形通用公式
with(toNum(shape), edge * neighbor * abs(sin(pi * angle / 180)) / 2)
calcArea.Parallelogram <- function(shape, ...) ## 平四通用公式
with(toNum(shape), edge * neighbor * abs(sin(pi * angle / 180)))
calcArea.default <- function(shape, ...) NA ## 默认不计算面积
ifNA <- function(x, y) if (is.na(x)) y else x
imputeNeighbor <- function(shape, ...) ## 泛型函数
UseMethod("imputeNeighbor")
imputeNeighbor.default <- function(shape, ...){
shape$neighbor <- with(
shape, ifNA(neighbor, edge))
return(shape)
}imputeAngle <- function(shape, ...) ## 泛型函数
UseMethod("imputeAngle")
imputeAngle.RegularTriangle <- function(shape, ...) {
shape$angle <- ifNA(shape$angle, 60)
return(shape)
}
imputeAngle.Square <- function(shape, ...) {
shape$angle <- ifNA(shape$angle, 90)
return(shape)
}
imputeAngle.ExactSquare <- imputeAngle.Square
imputeAngle.default <- function(shape, ...)
return(shape)newshapes <- shapes
newshapes$shapeclass <- c(
"Triangle", rep("Parallelogram", 4), "Triangle")
newshapes$shape <- c(
"Triangle", "Parallelogram", "Square", "Rhombus",
"ExactSquare", "RegularTriangle")
newshapes <- apply(newshapes, 1, function(x)
structure(as.list(x), class=unname(
x[c('shape', 'shapeclass')])))
str(newshapes)
List of 6
$ :List of 5
..$ shape : chr "Triangle"
..$ edge : chr "10"
..$ neighbor : chr "20"
..$ angle : chr "45"
..$ shapeclass: chr "Triangle"
..- attr(*, "class")= chr [1:2]
"Triangle" "Triangle"
$ :List of 5
..$ shape : chr "Parallelogram"
..$ edge : chr "10"
..$ neighbor : chr "20"
..$ angle : chr "60"
..$ shapeclass: chr "Parallelogram"
..- attr(*, "class")= chr [1:2]
"Parallelogram" "Parallelogram"
$ :List of 5
..$ shape : chr "Square"
..$ edge : chr "10"
..$ neighbor : chr "20"
..$ angle : chr NA
..$ shapeclass: chr "Parallelogram"
..- attr(*, "class")= chr [1:2]
"Square" "Parallelogram"
...newareas <- newshapes %>% lapply(imputeNeighbor) %>% lapply(imputeAngle) %>%
sapply(calcArea)
rbind(legacySolution=areas, oopSolution=newareas)
## [,1] [,2] [,3] [,4] [,5] [,6] ## legacySolution 70.71068 173.2051 200 70.71068 100 43.30127 ## oopSolution 70.71068 173.2051 200 70.71068 100 43.30127
Thank you!