【问题标题】:How to create a virtual reference class in R?如何在 R 中创建虚拟引用类?
【发布时间】:2014-02-04 05:42:30
【问题描述】:

我在help(ReferenceClasses) 中找不到太多关于虚拟/抽象类的信息——任何人都可以提供创建一个基本示例吗?此外,如何指定虚方法并强制子类必须实现它?

【问题讨论】:

    标签: r class oop reference-class


    【解决方案1】:

    参考类是 S4 类。所以也许你应该看到setClassClasses的帮助:

    这里是一个虚拟的例子:

    # virtual Base Class
    setRefClass( 
      Class="virtC", 
      fields=list( 
        .elt="ANY" 
      ),
      methods = list(
        .method = function(){
          print("Base virtual method is called")
        }
      ), 
      contains=c("VIRTUAL") 
    ) 
       
    ## child 1
    ## field as numeric and base .method is used
    setRefClass( 
      Class="childNum", 
      fields=list( 
        .elt="numeric" 
      ), 
      contains=c("virtC")  
    )
    
    
    ## child 2 
    ## field is char and .method is overwritten
    setRefClass( 
      Class="childChar", 
      fields=list( 
        .elt="character" 
      ), 
      methods = list(
        .method = function(){print('child method is called')}
      ), 
      contains=c("virtC") 
    ) 
    ##  new('virtA')          ## thros an error can't isntantiate it
    a = new("childChar",.elt="a")
    b =   new("childNum",.elt=1)
    
    b$.method()
    [1] "Base virtual method is called"
    
    a$.method()
    [1] "child method is called"
    

    【讨论】:

    • 谢谢,虽然虚拟类 virtC 的显式实例化被捕获,但似乎没有机制可以确保子类实际实现从父类继承的所有抽象方法——我仍然能够在没有实现$.method 的情况下声明类childChar。有什么方法可以纠正这种行为?
    • @MiloChen 那是因为 R 根本不知道抽象方法。如果您想强制覆盖 .method,您可以使用 stop( "virtC$.method() must be implemented" ) 在虚拟类中实现它。
    • @MiloChen 我只是补充一点,Class 是 virtual 而不是 abstract。我编辑我的示例以显示此功能。
    • 我害怕那个。我真诚地希望有某种机制来检查定义不明确的类,而不是依赖于引发运行时错误。我的意思是,他们已经对字段名称的本地分配实施了检查(field <- var 而不是 field <<- var)...
    【解决方案2】:

    这是我正在考虑采用的一种方法,用于从继承的虚拟“接口”中捕获未实现的方法。它不会静态捕获不正确的实现,但如果您尝试实例化一个没有实现所有接口方法的对象,它会出错。与其在调用未实现的函数时等待运行时错误,不如在您尝试创建对象时立即炸弹。

    辅助函数

    帮助函数在继承树中搜索接口。现在这个太基础了。我需要做的是爬树并检查自己继承接口类的父母......

    .get_interface_methods <- function(.self) {
    
      ## Get the environment of the class being instantiated
      env <- attributes(.self$.refClassDef)$refMethods
    
      ## get original interface methods
      supers <- selectSuperClasses(class(.self))
      methods <- unlist(lapply(supers, function(x) getRefClass(x)$methods()))
    
      ## check the body is NOT null in the concrete class environment
      funs <- Filter(is.function, lapply(methods, get, envir=env))
      null_fun_body <- vapply(Map(body, funs), is.null, T)
    
      ## return names of functions not implemented
      vapply(funs[null_fun_body], attr, "", which="name")
    }
    

    在实例化包含一个或多个接口的对象时调用的另一个辅助函数。

    .validate_interface <- function(.self) {
    
      methods <- get_interface_methods(.self)
    
      ## stop the world and print out the un-implemented methods
      if (length(methods) > 0L) {
        stop("Must implement interface methods: ", paste(methods, collapse = ", "))
      }
    }
    

    Interface 类只是在初始化期间调用 validate 函数。从 Interface 继承的类可以使用任何具有 NULL 主体的函数来注册接口方法。我为此创建了一个简单的助手。

    setRefClass(
      "Interface",
      methods = list(
      initialize = function() {
        validate(.self)
      }), contains="VIRTUAL")
    
    InterfaceMethod <- function() NULL
    

    接口

    在这里,我使用具有NULL 主体的虚拟方法创建了两个接口。

    ## Create an interface to be implemented
    setRefClass(
      "ITest1",
      contains=c("VIRTUAL", "Interface"),
      methods = list(
        foo = InterfaceMethod,
        bar = InterfaceMethod,
        baz = InterfaceMethod
    ))
    
    ## create a second interface
    setRefClass(
      "ITest2",
      contains=c("VIRTUAL", "Interface"),
      methods = list(
        spam = InterfaceMethod,
        ham  = InterfaceMethod
      ))
    

    实例化一个对象

    最后,我创建了一个非虚拟的类定义,它继承了我定义的两个接口。在定义中,我实现了foo&baz这两个接口函数,但没有实现barspamham

    Obj <- setRefClass(
      "Obj",
      contains = c("ITest1", "ITest2"),
      methods = list(
        foo = function() "Implemented!",
        baz = function() "Implemented!"
    ))
    

    当我尝试实例化这个对象时,我得到一个错误。

    > x <- Obj$new()
     Error in validate(.self) : 
      Must implement interface methods: bar, ham, spam
    

    【讨论】:

      猜你喜欢
      • 2023-03-24
      • 2020-04-03
      • 1970-01-01
      • 1970-01-01
      • 2013-09-23
      • 1970-01-01
      • 2014-09-16
      • 2021-07-10
      • 2021-03-27
      相关资源
      最近更新 更多