문제

현재 저는 소프트웨어 엔지니어링, 소프트웨어 디자인, 디자인 패턴 등에 대한 책을 많이 읽고 있습니다.완전히 다른 배경에서 온 것, 그것은 나에게 모두 새롭고 흥미로운 일이므로 특정 측면을 설명하기 위해 올바른 기술 용어를 사용하지 않는 경우에 대비해 양해해 주시기 바랍니다 ;-)

나는 결국 사용했다 참조 수업 (R의 OOP 방식) 대부분의 경우 객체 지향이 제가 하고 있는 많은 작업에 적합한 선택인 것 같기 때문입니다.

이제 누군가가 구현과 관련하여 좋은 조언이나 경험이 있는지 궁금합니다. MVC (모델 뷰 컨트롤러;또한 ~으로 알려진 MVP:Model View Presenter) 패턴, 가급적이면 참조 클래스를 사용합니다.

또한 다음과 같은 다른 "표준" 디자인 패턴에 관한 정보에도 매우 관심이 있습니다. 관찰자, 칠판 등등. 그러나 나는 이것을 너무 광범위한 질문으로 만들고 싶지 않습니다.가장 멋진 것은 최소한의 예제 코드를 보는 것이지만 포인터, "스키마", 다이어그램 또는 기타 아이디어도 크게 감사하겠습니다!

비슷한 내용에 관심이 있는 분들에게는 다음 책을 추천해 드립니다.

  1. 실용적인 프로그래머
  2. 디자인 패턴

업데이트 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()

구독이 관찰자에 기록되었습니다.

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. 컨트롤러는 모델과 뷰 사이의 모든 상호 작용을 제어하는 ​​일종의 "프록시"여야 합니까(일종의 "양방향"), 아니면 사용자 입력을 모델에 전파하는 역할만 담당해야 합니까(일종의 "단방향"입니까?)
도움이 되었습니까?

해결책

  1. 그것은 꽤 좋은 것처럼 보이지만, 나는 당신이 다른 수업에 추가 관찰자가 있는지, 일반적으로 컨트롤러가 관찰자인지에 추가 관찰자가 있는지 확신하지 못합니다. Java에서 배운 할 때 Java에서 그것을 배웠을 때, 이해하기가 쉽지 않았기 때문에 (Java는 좋은 부분을 숨 깁니다)

  2. 에이 작업을 수행하는 것이 정말 좋은 생각입니다.

  3. Yes and No.이 패턴에 대한 많은 다른 해석이 있습니다. 나는 물체에있는 방법을 갖고 싶습니다. 나는 그것이 모델에 속한다고 말할 것입니다. 간단한 예제는 GUI의 해결 단계를 보여주는 스도쿠 솔버가 될 것입니다. M, V 및 C로 분리 할 수있는 일부 부품으로 분리합시다. 원시 데이터 (2D Array 가능), Sudoku 함수 (Calc Next Step, ...), GUI, GUI를 알리는 사람, GUI, 단계가 계산되었습니다 나는 이것을 다음과 같이 넣을 것입니다 : M : 원시 데이터 + Sudoku 함수, C : GUI 입력에 관한 변경 / 모델에 대해 GUI를 알려주는 V : Logic이없는 V : GUI 다른 사람들은 스도쿠 기능을 컨트롤러에 넣고 옳고 문제가 발생할 수 있습니다

  4. "편도"컨트롤러가 전화를 걸고 뷰는 모델의 관찰자입니다 컨트롤러가 모든 것을 수행하는 것도 가능하고 모델을 모르고 서로를 알지 못하게 할 수도 있습니다 (모델 뷰 발표자를 봐)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top