设最底层的基类为Shape,Shape有周长和面积,圆Circle和椭圆Ellipse继承于Shape,设置计算周长的接口为circum(),计算面积的接口为area()。继承图表如下:
用R语言里的S4结构,可以很方便地实现接口和继承,详细代码如下:
//S4.R
# part1 -------------------------------------------------------------------
##定义基类Shape
setClass("Shape",slots = list(name="character"))
##定义圆形类Circle,继承Shape
setClass("Circle",contains = "Shape",slots = list(radius="numeric"),
prototype = list(radius=1))
##验证radius大于0
setValidity("Circle",function(object){
if(object@radius <= 0) stop("Radius is negative")
})
##定义计算面积的接口
setGeneric("area",function(obj,...) standardGeneric("area"))
##实现面积接口
setMethod("area","Circle",function(obj,...){
print("Area Circle Method")
pi * obj@radius^2
})
##定义周长的接口
setGeneric("circum",function(obj,...) standardGeneric("circum"))
##实现周长接口
setMethod("circum","Circle",function(obj,...){
2 * pi *obj@radius
})
##创建两个圆的实例---------------#
c1 <- new("Circle",name="c1")
c2 <- new("Circle",name="c2",radius=5)
# c1; c2
##计算两个圆的面积
area(c1)
area(c2)
##计算两个圆的周长
circum(c1)
circum(c2)
# part2 -------------------------------------------------------------------
##定义椭圆类Ellipse, 继承Shape
setClass("Ellipse",contains = "Shape",slots = list(radius="numeric"),
prototype = list(radius = c(1,1)))
##验证椭圆的半径
setValidity("Ellipse",function(object) {
if (length(object@radius) != 2 ) stop("It's not Ellipse.")
if (length(which(object@radius<=0))>0) stop("Radius is negative.")
})
##计算椭圆的面积
setMethod("area","Ellipse",function(obj,...){
print("Area Ellipse Method")
pi * prod(obj@radius)
})
##计算椭圆的周长
setMethod("circum","Ellipse",function(obj,...){
cat("Ellipse Circum: \n")
2*pi * sqrt((obj@radius[1]^2 + obj@radius[2]^2)/2 )
})
##创建椭圆的两个实例---------------------#
e1 <- new("Ellipse",name="e1");
e2 <- new("Ellipse",name="e2",radius=c(5,1))
##计算两个椭圆的面积
area(e1)
area(e2)
##计算两个椭圆的周长
circum(e1)
circum(e2)
效果如下:
方法二:当椭圆的长半径和短半径相等时,radius的两个值相等,形成的图形为圆形。利用这个特点,我们就可以重新设计圆与椭圆的关系。即椭圆是圆的父类,圆就是椭圆的子类。代码如下:
//S4a.R
# part1 -------------------------------------------------------------------
##面向对象
##Shape --> Ellipse -->Circle
##定义基类Shape
setClass("Shape",slots = list(name="character",shape="character"))
##定义获取图形的种类接口
setGeneric("getShape",function(obj,...) standardGeneric("getShape"))
##实现获取图形的种类接口
setMethod("getShape","Shape",function(obj,...){
cat(obj@shape,"\n")
})
##定义椭圆类Ellipse,继承Shape
setClass("Ellipse", contains = "Shape",slots = list(radius="numeric"),
prototype = list(radius=c(1,1),shape="Ellipse"))
##定义圆形Circle, 继承Ellipse
setClass("Circle",contains = "Ellipse",slots = list(radius="numeric"),
prototype = list(radius=1, shape="Circle"))
##定义area接口
setGeneric("area",function(obj,...) standardGeneric("area"))
##定义circum接口
setGeneric("circum",function(obj,...) standardGeneric("circum"))
##area接口的Ellipse实现
setMethod("area","Ellipse",function(obj,...){
cat("Ellipse Area: \n")
pi*prod(obj@radius)
})
##area接口的Circle实现
setMethod("area","Circle",function(obj,...){
cat("Circle Area: \n")
pi*obj@radius^2
})
##circum接口的Ellipse实现
setMethod("circum","Ellipse",function(obj,...){
cat("Ellipse Circum: \n")
2*pi*sqrt((obj@radius[1]^2 + obj@radius[2]^2)/2)
})
##circum接口的Circle实现
setMethod("circum","Circle",function(obj,...){
cat("Circle circum: \n")
2*pi*obj@radius
})
##创建实例
e1 <- new("Ellipse",name="e1",radius=c(2,5))
c1 <- new("Circle",name="c1",radius=2)
##计算面积
area(e1)
area(c1)
##计算周长
circum(e1)
circum(c1)
##获取图形的类型
getShape(e1)
getShape(c1)