“MVC” deki “Kontrolör” ne girer?


186

Ben MVC temel kavramları anlamak düşünüyorum - Model uygulamanın veri ve davranış içeriyor, Görünüm kullanıcıya görüntülemek sorumludur ve Denetleyici kullanıcı girişi ile ilgilenir. Ne hakkında belirsiz olduğum tam olarak neyi Kontrolör gider.

Diyelim ki oldukça basit bir uygulamam var (özellikle Java'yı düşünüyorum, ancak aynı prensiplerin başka yerlerde de geçerli olduğunu düşünüyorum). Kodumu app.model, app.viewve adlı 3 pakete düzenlerim app.controller.

İçinde app.modelpaketin, ben uygulamanın gerçek davranışlarını yansıtan birkaç sınıfları var. Bunlar extends Observableve uygun olduğunda güncellemeleri görüntülemek için setChanged()ve notifyObservers()tetiklemek için kullanın .

app.viewPaket kullanan bir sınıf (ya da ekranın farklı için çeşitli sınıflar) sahip olan javax.swinggörüntü işlemek için bileşenler. Bu bileşenlerin bazılarının Model'e geri beslenmesi gerekir. Doğru bir şekilde anlarsam, Görünüm'ün geri bildirim ile hiçbir ilgisi olmamalıdır - bu, Denetleyici tarafından ele alınmalıdır.

Peki Denetleyiciye gerçekte ne koyarım? public void actionPerformed(ActionEvent e)Kontrolöre yalnızca bir yöntemin çağrılmasıyla Görünümü koyabilir miyim ? Eğer öyleyse, Kontrolörde herhangi bir doğrulama vb. Yapılmalı mıdır? Öyleyse, Hata mesajlarını Görünüm'e nasıl geri gönderirim - bu Modelden tekrar geçmeli mi yoksa Denetleyici doğrudan doğrudan Görünüm'e göndermeli mi?

Doğrulama Görünüm'de yapılırsa, Denetleyiciye ne koyabilirim?

Uzun soru için özür dilerim, sadece süreç hakkındaki anlayışımı belgelemek istedim ve umarım birisi bu sorunu benim için netleştirebilir!

Yanıtlar:


520

Önerdiğiniz örnekte haklısınız: "Kullanıcı, arayüzde" bu öğeyi sil "düğmesini tıkladığında, temelde kontrolörün" sil "işlevini çağırması gerekir. Ancak denetleyicinin görünümün nasıl göründüğü hakkında hiçbir fikri yoktur ve bu nedenle görünümünüzde "hangi öğe tıklandı?"

Bir konuşma formunda:

Görünüm : "Hey, denetleyici, kullanıcı bana 4. maddenin silinmesini istediğini söyledi."
Denetleyici : "Hmm, kimlik bilgilerini kontrol ettikten sonra, bunu yapmasına izin verildi ... Hey, model, 4. maddeyi almanı ve silmek için ne yaparsan yapmanı istiyorum."
Model : "Öğe 4 ... anladı. Silindi. Sana geri döndük Denetleyici."
Denetleyici : "İşte, yeni veri kümesini toplayacağım. Sana geri dön, bak."
Görünüm : "Güzel, yeni seti şimdi kullanıcıya göstereceğim."

Bu bölümün sonunda bir seçeneğiniz vardır: görünüm ayrı bir istekte bulunabilir, "bana en son veri kümesini ver" ve dolayısıyla daha saf olabilir veya denetleyici yeni veri kümesini "sil " operasyon.


90
Bu diyalog, karşılaştığım MVC'nin en iyi açıklaması, teşekkürler!
Paul Walker

13
Her şey yolunda, ama doğrudan modelden okuma ile yanlış bir şey yok . "Kontrolörler veri polisi değil". Denetleyicileri zayıf tuttuğunu söyleyen bir doktrin de var. Görünüm Yardımcıları, görünümünüz tarafından tüketilmeye hazır veriler toplamak için mükemmel bir yerdir. Bazı veri erişim mantığını yeniden kullanmak için tam denetleyici yığınının gönderilmesi gerekmez. Daha fazla detay: rmauger.co.uk/2009/03/…
İstisna e

1
"İstisna e" ye katılıyorum. Modeldeki veriler, kontrolör değil birçok olay tarafından güncellenebilir ve bu nedenle bazı MVC tasarımlarında M, V'nin verilerin kirli olduğunu ve V'nin kendini yenileyebileceğini gösterir. C'nin bu durumda oynayacağı bir rol yoktur.
Mishax

68

Sorun MVCşu ki, insanlar görüşün, kontrolörün ve modelin birbirinden mümkün olduğunca bağımsız olması gerektiğini düşünüyorlar. Bir görüş ve denetleyici genellikle iç içe geçmezler - bunu düşünün M(VC).

Kontrolör, kullanıcı arayüzünün, özellikle GUI'lerle birlikte görünümde genellikle karışık olan giriş mekanizmasıdır. Yine de, görünüm çıktı ve denetleyici girdi. Bir görünüm genellikle karşılık gelen bir denetleyici olmadan çalışabilir, ancak bir denetleyici görünüm olmadan genellikle çok daha az kullanışlıdır. Kullanıcı dostu kontrolörler, görünümü kullanıcının girdisini daha anlamlı ve sezgisel bir şekilde yorumlamak için kullanır. Denetleyici konseptini görünümden ayırmayı zorlaştıran da budur.

Mühürlü bir kutudaki algılama alanındaki radyo kontrollü bir robotu model olarak düşünün.

Model, hiçbir çıkış (ekran) kavramı olmayan veya durum geçişlerini tetikleyen şey olan durum ve durum geçişleri ile ilgilidir. Robotun sahada pozisyonunu alabilirim ve robot pozisyonu nasıl değiştireceğini bilir (ileri / geri / sola / sağa doğru bir adım atın.

Denetleyici olmadan bir görünümü düşünün, örneğin robot konumunu izleyen başka bir odada ağdaki başka bir odada bulunan biri, (x, y) bir kaydırma konsolundan aşağı akış koordinasyonunu izler. Bu görüş sadece modelin durumunu gösteriyor, ancak bu adamın denetleyicisi yok. Yine, bu görüşü bir kontrolör olmadan hayal etmek kolaydır.

Görünümü olmayan bir denetleyiciyi düşünün, örneğin, radyo denetleyicisinin robotun frekansına ayarlanmış olduğu bir dolaba kilitli biri. Bu denetleyici girdi gönderir ve modele ne yaptıklarına dair hiçbir fikre sahip olmadan durum geçişlerine neden olur (eğer varsa). Öngörülmesi kolay, ancak görünümden bir tür geri bildirim olmadan gerçekten kullanışlı değil.

Çoğu kullanıcı dostu kullanıcı arayüzü, daha sezgisel bir kullanıcı arayüzü sağlamak için görünümü denetleyiciyle koordine eder. Örneğin, robotun mevcut konumunu 2 boyutlu olarak gösteren ve kullanıcının ekranda robotun önünde olan noktaya dokunmasına izin veren dokunmatik ekrana sahip bir görünüm / denetleyici hayal edin. Denetleyicinin, görüntü ile ilgili ayrıntılara ihtiyacı vardır, örneğin görünüm penceresinin konumu ve ölçeği ve robotun ekrandaki piksel konumuna göre dokunulan noktanın piksel konumu) bunu doğru bir şekilde yorumlamak için radyo denetleyicisi).

Sorunuzu henüz yanıtladım mı? :-)

Denetleyici, modelin geçiş durumuna neden olmak için kullanılan kullanıcıdan girdi alan herhangi bir şeydir. Görünümü ve denetleyiciyi ayrı tutmaya çalışın, ancak genellikle birbirine bağımlı olduklarını anlayın, bu nedenle aralarındaki sınır bulanıksa, yani görünüm ve denetleyicinin ayrı paketler olarak olması, temiz bir şekilde ayrılmayabilir. gibi, ama sorun değil. Görünüm modelden olduğu için denetleyicinin görünümden temiz bir şekilde ayrılmayacağını kabul etmeniz gerekebilir.

... Kontrolörde herhangi bir doğrulama vb. yapılmalı mı? Öyleyse, Hata mesajlarını Görünüm'e nasıl geri gönderirim - bu Modelden tekrar geçmeli mi yoksa Denetleyici doğrudan doğrudan Görünüm'e göndermeli mi?

Doğrulama Görünüm'de yapılırsa, Denetleyiciye ne koyabilirim?

Bağlantılı bir görüş ve denetleyicinin modelden geçmeden serbestçe etkileşim kurması gerektiğini söylüyorum. Denetleyici kullanıcının girişini alır ve doğrulamayı yapmalıdır (belki modelden ve / veya görünümden bilgi kullanarak), ancak doğrulama başarısız olursa, denetleyici ilgili görünümünü doğrudan güncelleyebilmelidir (örn. Hata mesajı).

Bunun için asit testi, bağımsız bir görüşün (diğer bir odadaki robot konumunu ağ üzerinden izleyen adamın) başka birinin doğrulama hatasının (örneğin dolaptaki adam) bir şey görüp görmeyeceğini sormasıdır. robota alandan çıkmasını söylemeye çalıştı). Genellikle, cevap hayırdır - doğrulama hatası durum geçişini engelledi. Devlette herhangi bir engel yoksa (robot hareket etmedi), diğer görüşleri söylemeye gerek yoktur. Dolaptaki adam, yasadışı bir geçişe (görünüm yok - kötü kullanıcı arayüzü) neden olmaya çalıştığı hakkında herhangi bir geri bildirim almadı ve başka kimsenin bunu bilmesine gerek yok.

Dokunmatik ekranı olan adam robotu sahadan göndermeye çalıştıysa, robotu algılama alanından göndererek öldürmemesini isteyen güzel bir kullanıcı dostu mesaj aldı, ama yine de, başka kimsenin bunu bilmesine gerek yok.

Diğer görünümler Eğer do Bu hatalarla ilgili bilmeniz gereken, o zaman etkili bir kullanıcıdan giriş ve herhangi çıkan hataların olduğunu söylediğini modelin parçası ve her şey biraz daha karmaşık olduğunu ...


23

İşte MVC'nin temelleri hakkında iyi bir makale .

Belirtir ...

Denetleyici - Denetleyici, görünümle etkileşimleri model tarafından gerçekleştirilecek eylemlere dönüştürür.

Başka bir deyişle, iş mantığınız. Denetleyici, kullanıcının görünümde yaptığı eylemlere yanıt verir ve yanıt verir. Doğrulamayı buraya koyun ve doğrulama başarısız olursa veya başarılı olursa uygun görünümü seçin (hata sayfası, mesaj kutusu, her neyse).

Fowler'te iyi bir makale daha var .


MVP, başvurduğunuz makalede tartışılan başka bir seçenektir, bkz. Martinfowler.com/eaaDev/ModelViewPresenter.html
Jon

Linkler için teşekkürler, kesinlikle ilginç bir okuma için yaparlar.
Paul Walker

18

MVC modeli yalnızca sunumu (= görünüm) iş mantığından (= model) ayırmanızı ister . Kontrolör kısmı sadece karışıklığa neden olmak için oradadır.


1
Tam olarak, şimdiye kadar hep düşündüğüm ama kimseye söyleyecek cesaretim olmadı .... ya da uygun kelimelerle gelemedim.
user1451111

1
Model-Görünüm-Karışıklık
Yağmur

10

Pratik olarak, kontrolör konseptini hiç bu kadar kullanışlı bulmamıştım. Kodumda katı model / görünüm ayrımı kullanıyorum, ancak açıkça tanımlanmış bir denetleyici yok. Gereksiz bir soyutlama gibi görünüyor.

Şahsen, tam gelişmiş MVC, fabrika tasarım deseni gibi görünüyor, çünkü kafa karıştırıcı ve aşırı karmaşık tasarıma kolayca yol açıyor. Bir mimari astronot olma .


9

Sorunuza dayanarak, Model'in rolü hakkında biraz puslu olduğunuz izlenimini edindim. Model, uygulamayla ilişkili verilere sabitlenmiştir; Uygulamanın bir veritabanı varsa, Modelin işi onunla konuşmak olacaktır. Ayrıca bu verilerle ilişkili herhangi bir basit mantığı işleyecektir; TABLE.foo == "Yaşasın!" ve TABLE.bar == "Huzzah!" sonra TABLE.field = "W00t!" olarak ayarlayın, sonra Modelin ilgilenmesini istersiniz.

Denetleyici, uygulamanın davranışının büyük bir kısmını ele almalıdır. Sorularınızı cevaplamak için:

Genel void actionPerformed (ActionEvent e) öğesini Denetleyicide yalnızca bir yönteme çağrı ile Görünüm'e koyabilir miyim?

Hayır derdim. Kontrolörde yaşaması gerektiğini söyleyebilirim; Görünüm, kullanıcı arabiriminden gelen verileri Denetleyiciye beslemeli ve Denetleyiciye yanıt olarak hangi yöntemlerin çağrılması gerektiğine karar vermelidir.

Eğer öyleyse, Kontrolörde herhangi bir doğrulama vb. Yapılmalı mıdır?

Doğrulamanızın büyük bir kısmı gerçekten Denetleyici tarafından yapılmalıdır; verilerin geçerli olup olmadığı sorusuna cevap vermeli ve eğer değilse, uygun hata mesajlarını Görünüm'e beslemelidir. Uygulamada, kullanıcı deneyimini iyileştirmek için View katmanına bazı basit sağlık kontrolleri ekleyebilirsiniz. (Öncelikle kullanıcı "Gönder" isabet anında bir hata mesajı almak isteyebilirsiniz öncelikle web ortamları düşünüyorum, tüm vidalı -> işlem -> yük sayfa döngüsü onları vida önce söylemeden önce .) Sadece dikkatli ol; çabaları gerekenden daha fazla çoğaltmak istemezsiniz ve birçok ortamda (yine web'i düşünüyorum), kullanıcı arayüzünden gelen herhangi bir veriyi bir pis pislik paketi olarak ele almak zorundasınız. sana kadar yalan söyler '

Öyleyse, Hata mesajlarını Görünüm'e nasıl geri gönderirim - bu Modelden tekrar geçmeli mi yoksa Denetleyici doğrudan doğrudan Görünüm'e göndermeli mi?

Görünüm, Denetleyici söyleyene kadar bundan sonra ne olacağını mutlaka bilmeyecek şekilde ayarlanmış bir protokolünüz olmalıdır. Kullanıcı bu düğmeyi tıklattıktan sonra hangi ekranı gösteriyorsunuz? Görünüm bilmiyor olabilir ve Denetleyici yeni aldığı verilere bakana kadar da bilmeyebilir. "Beklendiği gibi bu diğer ekrana git" veya "Bu ekranda kal ve bu hata mesajını göster" olabilir.

Deneyimlerime göre, Model ve Görünüm arasındaki doğrudan iletişim çok, çok sınırlı olmalı ve Görünüm, Model'in hiçbir veriyi doğrudan değiştirmemelidir; Kontrolörün işi bu olmalı.

Doğrulama Görünüm'de yapılırsa, Denetleyiciye ne koyabilirim?

Yukarıyı görmek; gerçek doğrulama Kontrolörde olmalıdır. Ve umarım şimdiye kadar Kontrolöre ne konması gerektiği konusunda bir fikriniz vardır. :-)

Kenarların etrafında biraz bulanıklaşabileceğini belirtmek gerekir; yazılım mühendisliği kadar karmaşık olan her şeyde olduğu gibi, karar çağrıları da bolca olacaktır. Sadece en iyi kararınızı kullanın, bu uygulama içinde tutarlı kalmaya çalışın ve öğrendiğiniz dersleri bir sonraki projeye uygulamaya çalışın.


7

Denetleyici gerçekten Görünümün bir parçasıdır. Görevi, isteği yerine getirmek için hangi hizmetlerin gerekli olduğunu, hizmet arayüzünün gerektirdiği nesnelere Mareşal değerlerini azaltmak, bir sonraki Görünümü belirlemek ve yanıtı bir sonraki Görünümün kullanabileceği bir forma dönüştürmek . Ayrıca atılan istisnaları da ele alır ve bunları kullanıcıların anlayabileceği Görünümler haline getirir.

Hizmet katmanı, kullanım durumlarını, iş birimlerini ve model nesnelerini bilen şeydir. Denetleyici her görünüm türü için farklı olacaktır; masaüstü, tarayıcı tabanlı, Flex veya mobil kullanıcı arayüzleri için aynı denetleyiciye sahip olmayacaksınız. Bu yüzden gerçekten kullanıcı arayüzünün bir parçası olduğunu söylüyorum.

Servis odaklı: işin yapıldığı yer burası.


3

Kontrolör öncelikle görünüm ve model arasındaki koordinasyon içindir.

Ne yazık ki, bazen uygulama ile karışıyor - küçük uygulamalarda bu çok da kötü değil.

Ben koymak öneririz:

public void actionPerformed(ActionEvent e)

denetleyicide. Ardından, görüşünüzdeki eylem dinleyiciniz denetleyiciye delege olmalıdır.

Doğrulama kısmına gelince, görünümü veya denetleyiciyi koyabilirsiniz, kişisel olarak denetleyiciye ait olduğunu düşünüyorum.

Kesinlikle Pasif Görünüm ve Supervising Presenter (ki aslında ne Model View Presenter bölünmüş olduğunu - en azından Fowler tarafından) tavsiye ederim. Görmek:

http://www.martinfowler.com/eaaDev/PassiveScreen.html

http://www.martinfowler.com/eaaDev/SupervisingPresenter.html


3

İşte kullandığım bir başparmak kuralı: Bu sayfadaki bir eylem için özel olarak kullanacağım bir prosedür ise , modele değil, denetleyiciye aittir. Model, veri depolama için yalnızca tutarlı bir soyutlama sağlamalıdır.

MVC anlaşıldığını ancak gerçekten anlamadıklarını düşünen geliştiriciler tarafından yazılan büyük bir webapp ile çalıştıktan sonra bunu buldum. Onların "denetleyicileri", başka hiçbir yerde denilmeyen sekiz sınıf statik sınıf yöntemine indirgenir: - / modellerini ad alanları yaratmanın yollarından biraz daha fazla yapmak. Bunu düzgün bir şekilde yeniden ayarlamak üç şey yapar: tüm SQL'i veri erişim katmanına (aka model) kaydırır, denetleyici kodunu biraz daha ayrıntılı ama çok daha anlaşılır hale getirir ve eski "model" dosyaları hiçbir şeye indirmez. :-)


1

ayrıca her bir Swing widget'ının üç MVC bileşenini içerdiği düşünülebilir: her birinin bir Modeli (yani ButtonModel), bir Görünümü (BasicButtonUI) ve bir Kontrolü (JButton'un kendisi) vardır.


1

Denetleyiciye ne koyduğunuz konusunda haklısınız. Modelin Görünümle etkileşime girmesinin tek yolu budur. Oluşturulan eylem Görünüm'e yerleştirilebilir, ancak asıl işlevsellik Denetleyici olarak işlev görecek başka bir sınıfa yerleştirilebilir. Bunu yapacaksanız, aynı alıcıya sahip tüm komutları soyutlamanın bir yolu olan Komut desenine bakmanızı öneririz. Konu için özür dilerim.

Her neyse, uygun bir MVC uygulaması sadece aşağıdaki etkileşimlere sahip olacaktır: Model -> Görünüm Görünümü -> Kontrolör Kontrolörü -> Görünüm

Başka bir etkileşimin olabileceği tek yer, Görünümü güncellemek için bir gözlemci kullanıyorsanız, Görünüm'ün Denetleyiciden ihtiyaç duyduğu bilgileri istemesi gerekecektir.


0

Anladığım kadarıyla, Controller kullanıcı arayüzü işlemlerinden uygulama düzeyindeki işlemlere çevirir. Örneğin, bir video oyununda, Denetleyici "fareyi bu kadar çok piksel" içine "bu şekilde ve böyle bir yöne bakmak istiyor" olarak çevirebilir. Bir CRUD uygulamasında çeviri, "bu şeyi yazdır" ama kavram aynı.


0

Bu nedenle, çoğunlukla Kullanıcı güdümlü girdi / eylemleri (ve görünüm, veriler ve açık _Model şeyler hariç her şey için _Logic) işlemek ve bunlara tepki vermek için Denetleyicileri kullanarak yaparız:

(1) (yanıt, tepki - webapp, kullanıcıya yanıt olarak "ne yapar")

-> Ana ()

-> handleSubmit_AddNewCustomer ()

-> verifyUser_HasProperAuth ()

(2) ("işletme" mantığı, web uygulamasının ne ve nasıl "düşündüğü") Blog_Logic

-> sanityCheck_AddNewCustomer ()

-> handleUsernameChange ()

-> sendEmail_NotifyRequestedUpdate ()

(3) (görünümler, portallar, web uygulamasının "görünümü") Blog_View

-> genWelcome ()

-> genForm_AddNewBlogEntry ()

-> genPage_DataEntryForm ()

(4) ( her blog * sınıfının _ construct () öğesinde elde edilen yalnızca tüm veri nesnesi, tüm webapp / bellek içi verilerini bir nesne olarak bir arada tutmak için kullanılır) Blog_Meta

(5) (temel veri katmanı, DB'lere okur / yazar) Blog_Model

-> saveDataToMemcache ()

-> saveDataToMongo ()

-> saveDataToSql ()

-> loaddata ()

Bazen C veya L'de bir yöntemin nereye konulacağı konusunda biraz karışırız. Ancak Model kaya gibi sağlam, kristal berraklığındadır ve tüm bellek içi veriler _Meta'da bulunduğundan, orada da beyinsizdir. . İleriye doğru en büyük sıçramamız, _Meta kullanımını benimsemekti, bu arada, bu çeşitli _C, _L ve _Model nesnelerinden tüm pislikleri temizledi, hepsini zihinsel olarak yönetmeyi kolaylaştırdı, artı, bir swoop'ta bize ne olduğunu verdi "Bağımlılık Enjeksiyonu" veya tüm verilerle birlikte tüm ortamın etrafından dolaşmanın bir yolu (bonusu "test" ortamının kolayca oluşturulmasıdır).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.