标签: reference-class

在R中实现标准软件设计模式(专注于MVC)

目前,我正在阅读很多关于软件工程,软件设计,设计模式等的内容.来自完全不同的背景,这对我来说都是新的迷人的东西,所以如果我没有使用正确的技术术语,请耐心等待我描述某些方面;-)

我最终在大部分时间都使用了引用类(R中的OOP方法),因为面向对象似乎是我正在做的很多东西的正确选择.

现在,我想知道是否有人在R中实现MVC(模型视图控制器;也称为MVP:模型视图展示器)模式方面有一些好的建议或经验,最好使用参考类.

我也对其他"标准"设计模式(如观察者,黑板等)的信息非常感兴趣,但我不想让这个问题过于宽泛.我想最酷的事情是看到一些最小的示例代码,但任何指针,"架构",图表或任何其他想法也将非常感谢!

对于那些对类似内容感兴趣的人,我真的可以推荐以下书籍:

  1. 务实的程序员
  2. 设计模式

更新2012-03-12

我最终想出了一个我对MVC的解释的一个小例子(可能不完全正确;-)).

包依赖性

require("digest")
Run Code Online (Sandbox Code Playgroud)

类定义观察者

setRefClass(
    "Observer",
    fields=list(
        .X="environment"
    ),
    methods=list(
        notify=function(uid, ...) {
            message(paste("Notifying subscribers of model uid: ", uid, sep=""))
            temp <- get(uid, .self$.X)
            if (length(temp$subscribers)) {
                # Call method updateView() for each subscriber reference
                sapply(temp$subscribers, function(x) {
                    x$updateView()        
                })
            }    
            return(TRUE)
        }
    )
)
Run Code Online (Sandbox Code Playgroud)

类定义模型

setRefClass(
    "Model",
    fields=list(
        .X="data.frame",
        state="character",
        uid="character",
        observer="Observer"
    ),
    methods=list(
        initialize=function(...) {
            # Make sure all …
Run Code Online (Sandbox Code Playgroud)

design-patterns r pass-by-reference reference-class

56
推荐指数
1
解决办法
2768
查看次数

新参考类的意义是什么?

显然,John Chambers 在版本2.12中将R的Reference Classes添加到了R中.网上似乎没有太多的信息,但他们称之为R5课程,这意味着他们与S3和S4课程处于同一水平.

问题:什么是引用类,它如何适应现有的类类型?

r reference-class

47
推荐指数
1
解决办法
7953
查看次数

动态生成引用类

我试图在R包中动态生成引用类,并且它被证明是相当困难的.以下是我采取的方法和遇到的问题:

我正在创建一个包,我希望能够在模式中动态读取并自动生成关联的引用类(想想SOAP).当然,这意味着我无法在包源中预先定义我的引用类.

我最初尝试使用简单的方法创建一个新类:

myClass <- setRefClass("NewClassName", fields=list(fieldA="character"))
Run Code Online (Sandbox Code Playgroud)

当然,它在交互式执行时工作正常,但是当包含在包源中时,我会收到locked binding错误.从我的阅读中看,这看起来是因为当交互式运行时,类信息存储在未锁定的全局环境中,而我的包的基本环境被锁定.

然后我发现了一个建议使用某些东西的线程:

myClass <- setRefClass("NewClassName", fields=list(fieldA="character"), where=globalenv())
Run Code Online (Sandbox Code Playgroud)

当我尝试构建软件包时,这实际上已经崩溃了R/Studio,所以我不知道它生成的错误的日志,但不幸的是,它当然没有用.

接下来我尝试在我的包中创建一个新环境,我可以使用它来存储这些引用类.所以我.classEnv <- new.env()在我的包源中添加了一行(不在任何函数内部),然后在创建新的引用类时尝试使用该类:

myClass <- setRefClass("NewClassName", fields=list(fieldA="character"), where=.classEnv) 
Run Code Online (Sandbox Code Playgroud)

这实际上似乎工作正常,但会产生以下警告:

> myClass <- setRefClass("NewClassName", where=.classEnv)
Warning message:
In getPackageName(where) :
  Created a package name, ‘2013-04-23 10:19:14’, when none found
Run Code Online (Sandbox Code Playgroud)

所以,出于某种原因,methods::getPackageName()我无法拿起我的新环境所在的软件包?

有没有办法以不同的方式创建我的新环境,以便getPackageName()能够正确识别包?我可以添加一些允许我帮助getPackageName()检测包的功能吗?如果我可以处理警告,或者我是否通过尝试动态创建它们而滥用引用类,这是否会起作用?

r reference-class

13
推荐指数
1
解决办法
410
查看次数

R参考类中的方法初始化

在尝试实现一些优化算法时,我注意到R引用类中有一些奇怪的行为.在特定的初始化方法中似乎存在一些幕后解析魔法,这使得难以使用匿名函数.下面是一个说明难度的示例:我定义了一个优化函数(f_opt),一个对其运行优化的函数,以及一个将这两个作为方法的引用类.奇怪的行为将在代码中更清晰

f_opt <- function(x) (t(x)%*%x)

do_optim_opt <- function(x) optim(x,f)
do_optim2_opt <- function(x)
  {
   f(x) #Pointless extra evaluation
   optim(x,f)
  }

optClass <- setRefClass("optClass",methods=list(do_optim=do_optim_opt,
                                 do_optim2=do_optim2_opt,
                                 f=f_opt))
oc <- optClass$new()
oc$do_optim(rep(0,2)) #Doesn't work: Error in function (par)  : object 'f' not found
oc$do_optim2(rep(0,2)) #Works. 
oc$do_optim(rep(0,2)) #Parsing magic has presumably happened, and now this works too. 
Run Code Online (Sandbox Code Playgroud)

它只是我,还是看起来像其他人的错误?

r reference-class

11
推荐指数
1
解决办法
438
查看次数

R参考类中的私人会员

是否可以在R引用类中包含私有成员字段.玩我的一些在线示例:

> Account <- setRefClass(    "ref_Account"
>      , fields = list(
>       number = "character"
>       , balance ="numeric")
>      , methods = list( 
>     deposit <- function(amount) {
>       if(amount < 0)   {
>         stop("deposits must be positive")
>       }
>       balance <<- balance + amount
>     }
>     , withdraw <- function(amount) {
>       if(amount < 0)   {
>         stop("withdrawls must be positive")
>       }
>       balance <<- balance - amount
>     }       
>   ) )
> 
> …
Run Code Online (Sandbox Code Playgroud)

r reference-class

11
推荐指数
2
解决办法
2399
查看次数

Roxygen2 - 如何@export引用类生成器?

例如,假设我有以下包调用Test,我想导出类A:

# In /R/Test.R:
#' @docType package
#' @import methods
#' @exportClass A
A <- setRefClass("A", methods = list(foo = identity))
Run Code Online (Sandbox Code Playgroud)

但是,在构建和加载后,使用A的生成器时出现以下错误:

> library(Test)
> A()$foo(1)
Error: could not find function "A"
Run Code Online (Sandbox Code Playgroud)

我检查过我的NAMESPACE文件内容很好:

exportClasses(A)
import(methods)
Run Code Online (Sandbox Code Playgroud)

出了什么问题?为什么不导出我的类生成器?

r package roxygen reference-class roxygen2

10
推荐指数
1
解决办法
1706
查看次数

R参考类中的非标准集函数

是否有可能获得语法

foo$bar(x) <- value
Run Code Online (Sandbox Code Playgroud)

工作在哪里foo是一个引用类对象,bar是一个方法?即是可以做"子集分配"并将"替换函数"作为参考类中的方法吗?

是否可以使用其他OO系统获得语法?

示例: 我将用一个用例说明.想象一个引用类,Person它包含一个人的一些基本信息.特别是,一个叫做的字段fullname名为list:

PersonRCGen <- setRefClass("Person",
                           fields = list(
                             fullname = "list",
                             gender = "character"
                           ))
Run Code Online (Sandbox Code Playgroud)

接下来,我们应该定义一些方法来获取和设置fullnames列表中的特定名称(尝试)给出上面的语法/接口.到目前为止,我最好的尝试是:

PersonRCGen$methods(
  name = function(x) { # x is the dataset,
    .self$fullname[[x]]
  },
  `name<-` = function(x, value) {
    .self$fullname[[x]] <- value
  }
)
Run Code Online (Sandbox Code Playgroud)

这里的命名也应该说明我正在尝试做什么.

我们初始化一个新对象:

a_person <- PersonRCGen$new(fullname = list(first = "Jane", last = "Doe"),
                            gender = "F")
Run Code Online (Sandbox Code Playgroud)

fullname直接访问字段并通过定义的get函数访问名字和姓氏按预期工作:

a_person$fullname
#$`first`
#[1] "Jane"
# 
#$last
#[1] …
Run Code Online (Sandbox Code Playgroud)

r reference-class

10
推荐指数
1
解决办法
152
查看次数

在R中的引用类的initialize()方法中自动赋值

我正在使用一个带有几十个字段的引用类.我已经设置了一个initialize()采用列表对象的方法.虽然有些字段依赖于列表元素的进一步计算,但大多数字段都是从列表元素直接分配的:

fieldA <<- list$A
fieldB <<- list$B
Run Code Online (Sandbox Code Playgroud)

我当时觉得自动化这个很好.举一个R伪代码的例子(这个例子显然不起作用):

for (field in c('A', 'B', 'C', 'D'))
   field <<- list[[field]]
Run Code Online (Sandbox Code Playgroud)

我已经尝试过几次结束运行<<-,例如:

for field in c('A', 'B', 'C', 'D'))
  do.call('<<-' c(field, list[[field]])) 
Run Code Online (Sandbox Code Playgroud)

但没有骰子.

我的猜测是,在目前的参考类化身中,这种行为根本不可能,但是认为在SO土地上有人知道有更好的方法可以做到这一点可能是值得的.

r reference-class

8
推荐指数
1
解决办法
2355
查看次数

运算符重载R中的函数 - 奇怪的行为

不幸的是,像(f+g)(3)f和g这两个都是一元函数的东西在R中不起作用.因此,我尝试以下列方式重载"+"运算符以获得一元函数:

"+.function" = function(e1, e2){
  return(function(x) e1(x) + e2(x))
}
Run Code Online (Sandbox Code Playgroud)

但如果我尝试使用它,这什么都不做.代码

 a = function(x) 2*x
 (a+a)(2)
Run Code Online (Sandbox Code Playgroud)

产生相同的错误,如果+.function没有定义.

通过一段时间的游戏,我发现事实上有可能以这种方式添加函数:如果函数是引用类的成员函数,这是有效的!即,以下代码(连同上面的"+"定义)

clsA = setRefClass("clsA", 
  methods = list(
    b = function(x) 2*x
  ))

inst_a = clsA$new()
(inst_a$b + inst_a$b)(2)
Run Code Online (Sandbox Code Playgroud)

返回"8"(如预期的那样).因此,我已经为我的问题找到了某种解决方法.现在我的问题是:

这种奇怪行为的原因是什么?为什么不+.function关心"通常"功能而是关注类成员函数?有谁知道如何将操作员"扩展"到通常的功能?

oop r class function reference-class

8
推荐指数
1
解决办法
221
查看次数

在检索S4参考类的字段值时,避免考虑封闭帧

我是S4参考类的忠实粉丝,因为它们允许混合编程风格(功能/按值传递与oop/pass-by-reference; 示例),从而大大提高了灵活性.

但是,当我要求它通过方法检索某个字段值时,我认为我刚刚遇到了关于R扫描环境/帧的方式的不良行为$field()(请参阅帮助页面).问题是,如果在实际的本地/目标环境中找不到所需的字段(这将构成S4参考类的环境),R似乎也会查看封闭的环境/框架,即它就像运行一样get(<objname>, inherits=TRUE)(请参阅帮助)页面).

实际问题

为了具有R只是看在本地/目标的环境,我的想法是这样$field(name="<fieldname>", inherits=FALSE),但$field()没有一个...说法,让我通过inherits=FALSE一起get()(我猜是沿途某处调用).这有解决方法吗?


代码示例

对于那些对更多细节感兴趣的人:这是一个说明行为的小代码示例

setRefClass("A", fields=list(a="character"))

x <- getRefClass("A")$new(a="a")
Run Code Online (Sandbox Code Playgroud)

有一个领域aA,所以它在目标环境中找到,返回的值:

> x$field("a")
[1] "a"
Run Code Online (Sandbox Code Playgroud)

如果我们尝试访问不是引用类的字段但恰好具有与工作空间/搜索路径中的某个其他对象的名称相同的字段(在本例中"lm"),则情况会有所不同:

require("MASS")
> x$field("lm")

function (formula, data, subset, weights, na.action, method = "qr", 
    model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
    contrasts = NULL, offset, ...) 
{ …
Run Code Online (Sandbox Code Playgroud)

oop r pass-by-reference s4 reference-class

8
推荐指数
1
解决办法
198
查看次数