【问题标题】:Using multiple constructors for R classes and subclasses为 R 类和子类使用多个构造函数
【发布时间】:2019-03-20 01:30:21
【问题描述】:

我想在我的 R S4 类中使用多个构造函数。

我有一个具有三个插槽的对象。为了制作那个对象,有时我只想直接给出三个插槽的值。但有时我想提供一个矩阵,我有一个函数可以接受一个矩阵并返回这三个插槽应该是什么。

起初,我似乎可以编写一个函数作为构造函数。所以我可以写objectFromMatrix(matrix) --> object with three slots。问题是我也有从该主类继承的子类,我也希望能够与它们一起使用该构造函数。

所以我可以只为每个子类编写函数作为额外的构造函数,但这会有点乏味,而且不像超级 OO。

为了使我的问题更具体一些,我将尝试在下面编写一个最小的示例。我将用 Java 编写它,但我有点生疏,所以如果它没有意义,请告诉我。


所需的结构,在 Java 中:

// An abode is a place where you live and it has a size
class Abode {
    int size = 1;

    // Main constructor that just assigns args to fields
    Abode(int size) {
        this.size = size;
    }

    // Alternative constructor that takes in a different datatype
    // and computes args to assign to fields
    Abode(string description) {
        if(description eq "Large") {
            this.size = 5;
        }

        if(description eq "Small") {
            this.size = 1;
        }
}

// To keep it simple, a house is just an abode with a name
class House extends Abode {
        String name;

        House(int size, String name) {
                super(size);
                this.name = name;
        }

        House(string size, String name) {
                super(size);
                this.name = name;
        }
}

这个实现效果很好,因为我可以调用Abode("big")House("big", "Casa de me"),这两个都被传递给我在Abode 类中构建的额外构造函数。


跟上房子的类比,这是我在 R 中能做到的最好的:

# An abode is a place you live and it has a size
setClass("Abode",
         slots = 
             list(size = "numeric")
)

# Alternative constructor that takes in a different datatype
# and computes args to assign to fields
abode_constructor_2 <- function(sizeString) {
    if (sizeString == "big") {return new("Abode", size = 5)}
    if (sizeString == "small") {return new("Abode", size = 1)}
}

# A house is an abode with a name
setClass("House",
         slots = 
             list(name = "string"),
         contains = "Abode"
)

# I already defined this constructor but I have to do it again
house_constructor_2 <- function(sizeString, name) {
    if (sizeString == "big") {return new("House", size = 5, name = name)}
    if (sizeString == "small") {return new("House", size = 1, name = name)}
}

如果有帮助,这里是这个问题出现的真实背景的一个最小示例。我为Sensor 类定义了一个额外的构造函数sensor_constructor_2,作为一个函数。但是,当我有一个继承自Sensor 的类时,我必须重新创建该构造函数。

# A sensor has three parameters
setClass("Sensor",
         slots = 
             list(Rmin = "numeric", Rmax = "numeric", delta = "numeric")
)

# I also like to make sensors from a matrix
sensor_constructor_2 <- function(matrix) {
    params <- matrix_to_params(matrix)
    return (new("Sensor", Rmin = params[1], Rmax = params[2], delta = params[3]))
}


# A redoxSensor is just a sensor with an extra field
setClass("redoxSensor",
         slots = 
             list(e0 = "numeric"),
         contains = "Sensor"
)

# Goal: make this extra constructor unnecessary by making sensor_constructor_2 a property of the sensor class
extraConstructor_redox <- function(matrix, e0) {
    params <- matrix_to_params(matrix)
    return (new("redoxSensor", Rmin = params[1], Rmax = params[2], delta = params[3]), e0 = e0)
}

【问题讨论】:

  • 首先考虑您是否真的需要S4。根据我的经验,S3 可以在 99% 的时间内完成工作,而且复杂性要低得多
  • 当然,这是有道理的。我在这里选择使用 S4 作为个人偏好——我对 OO 不是很有信心,我认为额外的结构将帮助我远离设计错误,但我会更多地考虑使用 S3。无论哪种方式,如果您(或任何正在阅读的人)可以使用 S3 课程回答我的问题,请这样做!

标签: r s4


【解决方案1】:

没有理由不能通过使用默认参数和一些额外的逻辑来使用一个 S4 构造函数来做到这一点,类似于

setClass("Abode",
  slots = list(size = "numeric")
) -> Abode

setClass("House",
  slots = list(name = "character"),
  contains = "Abode"
) -> House

createDwelling <- function(size=0,name,sizeString){
  if(!missing(sizeString)){
    if(sizeString == "Large") size <- 5
    else if(sizeString == "Small") size <- 1
    else stop("invalid sizeString")
  }
  if(missing(name)) return(Abode(size=size))
  else return(House(size=size,name=name))
}

示例用法:

> createDwelling(size=3)
An object of class "Abode"
Slot "size":
[1] 3

> createDwelling(sizeString="Small")
An object of class "Abode"
Slot "size":
[1] 1

> createDwelling(sizeString="Small",name="my house")
An object of class "House"
Slot "name":
[1] "my house"

Slot "size":
[1] 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-28
    • 1970-01-01
    • 2022-10-17
    • 1970-01-01
    相关资源
    最近更新 更多