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

我最后使用引用类(在R中的一种方式)大部分时间,因为对象方向似乎是我正在做的很多东西的正确选择。

现在,我想知道是否有人对实现 mvc (模型视图控制器;也称为 mvp :mode视图介绍)模式,优选使用参考类。

我也非常兴趣关于其他“标准”设计模式,例如观察者黑板等,但我不想使这个太广泛的问题。我猜最酷的事情是看到一些最小的示例代码,但是任何指针,“架构”,图表或任何其他想法也将是非常理解的!

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

  1. 务实程序员
  2. 设计模式
  3. 更新2012-03-12

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

    包依赖性

    require("digest")
    
    .

    类定义观察者

    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)
            }
        )
    )
    
    .

    类定义模型

    setRefClass(
        "Model",
        fields=list(
            .X="data.frame",
            state="character",
            uid="character",
            observer="Observer"
        ),
        methods=list(
            initialize=function(...) {
                # Make sure all inputs are used ('...')
                .self <- callSuper(...)
                # Ensure uid
                .self$uid <- digest(c(.self, Sys.time()))
                # Ensure hash key of initial state
                .self$state <- digest(.self$.X)
                # Register uid in observer
                assign(.self$uid, list(state=.self$state), .self$observer$.X)
                .self
            },
            multiply=function(x, ...) {
                .self$.X <- .X * x 
                # Handle state change
                statechangeDetect()
                return(TRUE)
            },
            publish=function(...) {
                message(paste("Publishing state change for model uid: ", 
                    .self$uid, sep=""))
                # Publish current state to observer
                if (!exists(.self$uid, .self$observer$.X)) {
                    assign(.self$uid, list(state=.self$state), .self$observer$.X)
                } else {
                    temp <- get(.self$uid, envir=.self$observer$.X)
                    temp$state <- .self$state
                    assign(.self$uid, temp, .self$observer$.X)    
                }
                # Make observer notify all subscribers
                .self$observer$notify(uid=.self$uid)
                return(TRUE)
            },
            statechangeDetect=function(...) {
                out <- TRUE
                # Hash key of current state
                state <- digest(.self$.X)
                if (length(.self$state)) {
                    out <- .self$state != state
                    if (out) {
                    # Update state if it has changed
                        .self$state <- state
                    }
                }    
                if (out) {
                    message(paste("State change detected for model uid: ", 
                       .self$uid, sep=""))
                    # Publish state change to observer
                    .self$publish()
                }    
                return(out)
            }
        )
    )
    
    .

    类定义控制器和视图

    setRefClass(
        "Controller",
        fields=list(
            model="Model",
            views="list"
        ),
        methods=list(
            multiply=function(x, ...) {
                # Call respective method of model
                .self$model$multiply(x) 
            },
            subscribe=function(...) {
                uid     <- .self$model$uid
                envir   <- .self$model$observer$.X 
                temp <- get(uid, envir)
                # Add itself to subscribers of underlying model
                temp$subscribers <- c(temp$subscribers, .self)
                assign(uid, temp, envir)    
            },
            updateView=function(...) {
                # Call display method of each registered view
                sapply(.self$views, function(x) {
                    x$display(.self$model)    
                })
                return(TRUE)
            }
        )
    )
    setRefClass(
        "View1",
        methods=list(
            display=function(model, x=1, y=2, ...) {
                plot(x=model$.X[,x], y=model$.X[,y])
            }
        )
    )
    setRefClass(
        "View2",
        methods=list(
            display=function(model, ...) {
                print(model$.X)
            }
        )
    )
    
    .

    表示虚拟数据的类定义

    setRefClass(
        "MyData",
        fields=list(
            .X="data.frame"
        ),
        methods=list(
            modelMake=function(...){
                new("Model", .X=.self$.X)
            }
        )
    )
    
    .

    创建实例

    x <- new("MyData", .X=data.frame(a=1:3, b=10:12))
    
    .

    调查模型特征和观察者状态

    mod <- x$modelMake()
    mod$.X
    
    > mod$uid
    [1] "fdf47649f4c25d99efe5d061b1655193"
    # Field value automatically set when initializing object.
    # See 'initialize()' method of class 'Model'.
    
    > mod$state
    [1] "6d95a520d4e3416bac93fbae88dfe02f"
    # Field value automatically set when initializing object.
    # See 'initialize()' method of class 'Model'.
    
    > ls(mod$observer$.X)
    [1] "fdf47649f4c25d99efe5d061b1655193"
    
    > get(mod$uid, mod$observer$.X)
    $state
    [1] "6d95a520d4e3416bac93fbae88dfe02f"
    
    .

    请注意,初始化时,对象的UID已在观察者中自动注册。这样,控制器/视图可以订阅通知,我们有一个1:n的关系。

    实例化视图和控制器

    view1 <- new("View1")
    view2 <- new("View2")
    cont  <- new("Controller", model=mod, views=list(view1, view2))
    
    .

    订阅

    控制器订阅底层模型的通知

    cont$subscribe()
    
    .

    请注意,订阅已登录Observer

    get(mod$uid, mod$observer$.X)
    
    .

    显示注册视图

    > cont$updateView()
      a  b
    1 1 10
    2 2 11
    3 3 12
    [1] TRUE
    
    .

    还有一个打开的绘图窗口。

    修改模型

    > cont$model$multiply(x=10)
    State change detected for model uid: fdf47649f4c25d99efe5d061b1655193
    Publishing state change for model uid: fdf47649f4c25d99efe5d061b1655193
    Notifying subscribers of model uid: fdf47649f4c25d99efe5d061b1655193
       a   b
    1 10 100
    2 20 110
    3 30 120
    [1] TRUE
    
    .

    请注意,由于底层模型将其状态更改发布到观察者的底层模型,这两个已注册视图都会自动更新,这反过来通知所有订阅者(即,控制器)。

    打开问题

    这是我觉得我不完全理解:

    1. 这是MVC模式的稍微正确实现吗?如果没有,我做错了什么?
    2. 应该“处理”方法(例如,为模型“属于”到模型或控制器类的方法)(例如,占用数据,占用子集等)。到目前为止,我始终定义了一个特定对象可以“执行”的所有物体作为这个非常对象的方法。
    3. 如果控制器是控制模型和视图之间的每个交互的“代理”(类型的“两种方式”),或者它只负责将用户输入传播到模型(单向的类型“?< / li>
有帮助吗?

解决方案

  1. 它看起来非常好,但我不太确定为什么你的其他课程额外的观察者(也许你可以告诉我)通常,控制器是一个观察者。在R中这样做是一个非常好的主意因为当我在Java中学到的时候,它并不是那么容易理解(Java隐藏一些好的部分)

  2. 是和否。此模式有许多不同的解释。我喜欢在对象中有方法,我会说它属于模型。 一个简单的例子是Sudoku求解器,它显示了GUI中的求解步骤。让我们将其分成一些可以分成M,V和C:原始数据(2D阵列),数独函数(计算下一步,......),GUI,告诉GUI的一个新的计算步骤 我将它放在这样的:M:原始数据+数独函数,C:谁告诉GUI关于GUI输入的更改/模型,V:GUI没有任何逻辑 其他人将Sudoku函数放入控制器中,也可以对某些问题更好地工作

  3. 可以拥有像你称之为的“一种方式”控制器,并且视图是模型的观察者 也可以让控制器做一切和模型,并且查看不知道彼此(看起来是一个关于那个)的模型视图演示者)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top