تنفيذ البرامج القياسية أنماط التصميم (التركيز على MVC) في R

StackOverflow https://stackoverflow.com//questions/9674027

سؤال

حاليا أنا أقرأ الكثير عن برامج الهندسة, برامج تصميم, تصميم أنماط الخ.يأتي من خلفية مختلفة تماما, هذا هو كل جديد رائع بالنسبة لي, لذا يرجى تتحمل معي في الحالة أنا لا تستخدم الصحيح المصطلحات التقنية في وصف بعض جوانب ;-)

انتهى بي الأمر باستخدام إشارة الطبقات (طريقة OOP في ص) أكثر من مرة بسبب كائن التوجه يبدو أن الخيار الصحيح عن الكثير من الأشياء التي أقوم به.

الآن أنا أتساءل عما إذا كان أي شخص لديه بعض النصائح الجيدة أو بعض الخبرة فيما يتعلق بتنفيذ MVC (نموذج عرض المراقب المالي ؛ المعروف أيضا باسم MVP:نموذج عرض مقدم) في نمط R ، ويفضل استخدام إشارة الطبقات.

أود أيضا أن تكون مهتمة جدا في المعلومات المتعلقة أخرى "المعيار" أنماط التصميم مثل المراقب, السبورة الخ ، ولكن لا نريد أن نجعل هذا واسع جدا من سؤال.أعتقد أن أروع شيء أن نرى بعض الحد الأدنى رمز المثال ، ولكن أي مؤشر "المخطط", الرسم أو أي فكرة أخرى أيضا سوف يكون موضع تقدير كبير!

للراغبين في الأشياء مماثلة, أنا حقا أن يوصي الكتب التالية:

  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. أنها تبدو جيدة جدا, ولكن أنا لست متأكدا من السبب لديك مراقب إضافية إلى فئات أخرى (ربما يمكنك إخباري) عادة ما تحكم مراقب.انها فكرة جيدة للقيام بذلك في R لأنه عندما علمت أنه في جافا أنه ليس من السهل أن نفهم (جافا يخفي بعض أجزاء جيدة)

  2. نعم و لا.هناك العديد من التفسيرات المختلفة من هذا النمط.أحب أن يكون الطرق في الكائن ، أود أن أقول أنه ينتمي إلى النموذج.مثال بسيط سيكون سودوكو حلالا يوضح خطوات حل في واجهة المستخدم الرسومية.دعونا تقسيمه إلى بعض الأجزاء التي يمكن فصلها إلى M, V C:البيانات الخام (2D array ربما) ، سودوكو وظائف (احسب الخطوة التالية،...) ، واجهة المستخدم الرسومية شخص يحكي واجهة المستخدم الرسومية التي خطوة جديدة كانت محسوبة كنت وضعت مثل هذا:م:البيانات الخام + سودوكو وظائف C:الذي يحكي واجهة المستخدم الرسومية حول التغييرات / نموذج عن واجهة المدخلات V:واجهة المستخدم الرسومية دون أي منطق والبعض الآخر وضع سودوكو وظيفة في وحدة تحكم ، هو أيضا صحيح و قد تعمل على نحو أفضل بالنسبة لبعض المشاكل

  3. فمن الممكن أن يكون "طريقة واحدة" تحكم مثل تسميه والرأي مراقب من نموذج فإنه من الممكن أيضا أن السماح تحكم تفعل كل شيء و نموذج عرض لا تعرف بعضها البعض (انظر نموذج عرض مقدم هذا عن ذلك)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top