MVVM ve servis düzeni


14

MVVM desenini kullanarak bir WPF uygulaması inşa ediyorum. Şu anda, görünüm modellerim modelleri (görünüm modeliyle nasıl ilgili değil) almak ve bunları görünüm modellerine dönüştürmek için hizmet katmanını çağırıyor. Viewmodel için gerekli hizmeti geçmek için yapıcı enjeksiyon kullanıyorum.

Kolayca test edilebilir ve birkaç bağımlılığa sahip görünüm modelleri için iyi çalışır, ancak karmaşık modeller için viewModels oluşturmaya çalıştığımda, içine enjekte edilmiş çok sayıda hizmet içeren bir yapıcıya sahibim (her bağımlılıkları ve mevcut tüm değerlerin listesini almak için bir tane) örneğin bir itemSource kaynağına bağlamak için). Böyle birden çok hizmeti nasıl ele alacağımı merak ediyorum ve yine de kolayca test edebileceğim bir görünüm modeline sahibim.

Birkaç çözüm düşünüyorum:

  1. Arabirim olarak kullanılabilir tüm hizmetleri içeren bir hizmet singletonu (IServices) oluşturma. Örnek: Services.Current.XXXService.Retrieve (), Services.Current.YYYService.Retrieve (). Bu şekilde, içinde tonlarca hizmet parametresi olan büyük bir kurucum yok.

  2. ViewModel tarafından kullanılan hizmetler için bir cephe oluşturma ve bu nesneyi viewmodelimin kasasına geçirme. Ama sonra, her karmaşık görünüm modelim için bir cephe oluşturmam gerekecek ve biraz fazla olabilir ...

Sizce bu tür mimariyi uygulamanın "doğru" yolu nedir?


Ben bunu yapmak için "doğru" yolu hizmetleri çağıran ve ViewModel oluşturmak için gereken her döküm yapar ayrı bir katman oluşturmak olduğunu düşünüyorum. ViewModels'leriniz kendilerini oluşturmaktan sorumlu olmamalıdır.
Amy Blankenship

@AmyBlankenship: Görünüm Modelleri kendilerini yaratmak zorunda kalmamalı (hatta zorunlu olarak oluşturabilmelidir), ancak bazen başka görünüm modelleri oluşturmaktan kaçınılmaz olarak sorumlu olacaktır . Otomatik fabrika desteğine sahip bir IoC konteyneri burada çok yardımcı oluyor.
Aaronaught

"Will bazen" ve "gerekir" iki farklı hayvan;)
Amy Blankenship

@AmyBlankenship: Görünüm modellerinin başka görünüm modelleri oluşturmamasını mı öneriyorsunuz? Yutmak zor bir hap. Görünüm modellerinin newdiğer görünüm modellerini oluşturmak için kullanmaması gerektiğini söyleyebilirim , ancak "yeni belge" düğmesine veya menüye tıklamanın yeni bir sekme ekleyeceği veya yeni bir pencere açacağı bir MDI uygulaması kadar basit bir şey düşünün. Kabuk / iletken gerekir yeni örneklerini oluşturmak mümkün bir şey birine veya bir birkaç dolaylama katmanları arkasında gizli olsa bile,.
Aaronaught

Kesinlikle bir Görüşün bir yerde yapılmasını talep etme yeteneğine sahip olmalıdır. Ama bunu kendisi yapmak için mi? Benim dünyamda değil :). Ama sonra tekrar, içinde yaşadığım dünyada VM'ye "Sunum Modeli" diyoruz.
Amy Blankenship

Yanıtlar:


22

Aslında, bu çözümlerin her ikisi de kötü.

Arabirim olarak kullanılabilir tüm hizmetleri içeren bir hizmet singletonu (IServices) oluşturma. Örnek: Services.Current.XXXService.Retrieve (), Services.Current.YYYService.Retrieve (). Bu şekilde, içinde tonlarca hizmet parametresi olan büyük bir kurucum yok.

Bu, esasen bir anti-desen olan Servis Bulucu Kalıbıdır . Bunu yaparsanız, görünüm modelinin özel uygulamasına bakmadan gerçekte neye bağlı olduğunu artık anlayamayacaksınız, bu da test etmeyi veya yeniden düzenlemeyi çok zorlaştıracaktır.

ViewModel tarafından kullanılan hizmetler için bir cephe oluşturma ve bu nesneyi viewmodelimin kasasına geçirme. Ama sonra, her karmaşık görünüm modelim için bir cephe oluşturmam gerekecek ve biraz fazla olabilir ...

Bu bir anti-desen değil, bir kod kokusu. Esasen bir parametre nesnesi oluşturuyorsunuz , ancak PO yeniden düzenleme modelinin noktası, sık ve çok farklı yerlerde kullanılan parametre kümeleriyle uğraşmaktır , oysa bu parametre yalnızca bir kez kullanılır. Bahsettiğiniz gibi, gerçek bir fayda sağlamak için çok fazla kod şişmesi yaratacak ve çok sayıda IoC kapsayıcısı ile hoş oynamayacaktır.

Aslında, yukarıdaki stratejilerin her ikisi de genel meseleyi gözden kaçırmaktadır, yani görünüm modelleri ve hizmetleri arasında çiftleşme çok yüksektir . Basitçe gizleme bir hizmet bulucuda bu bağımlılıkları veya parametre nesnesi aslında vermez değiştirmek görünüm modeli bağlıdır kaç diğer nesneler.

Bu görünüm modellerinden birini nasıl test edeceğinizi düşünün. Kurulum kodunuz ne kadar büyük olacak? Çalışması için kaç şeyin başlatılması gerekiyor?

MVVM ile başlayan birçok insan , tüm ekran için temel olarak yanlış yaklaşım olan görünüm modelleri oluşturmaya çalışır . MVVM tamamen kompozisyonla ilgilidir ve birçok işlevi olan bir ekran, her biri sadece bir veya birkaç dahili modele / hizmete bağlı olan birkaç farklı görünüm modelinden oluşmalıdır. Birbirleriyle iletişim kurmaları gerekiyorsa, bunu pub / sub (mesaj komisyoncusu, olay otobüsü vb.)

Aslında yapmanız gereken, daha az bağımlılığa sahip olmaları için görünüm modellerinizi yeniden düzenlemektir . Daha sonra, toplam bir "ekrana" ihtiyacınız varsa, daha küçük görünüm modellerini toplamak için başka bir görünüm modeli oluşturursunuz. Bu toplu görüntüleme modelinin kendi başına çok fazla bir şey yapması gerekmediğinden, anlaşılması ve test edilmesi de oldukça kolaydır.

Bunu düzgün bir şekilde yaptıysanız, sadece koda bakmaktan açıkça anlaşılmalıdır, çünkü kısa, özlü, spesifik ve test edilebilir görünüm modellerine sahip olacaksınız.


Evet, muhtemelen bunu yapacağım! Çok teşekkürler efendim.
alfa-alfa

Zaten bunu denediğini varsaymıştım, ancak başarılı olamadı. @ alfa-alfa
Euphoric

@Euphoric: Bu konuda nasıl "başarılı değilsiniz"? Yoda'nın dediği gibi: Yap ya da yapma, deneme yok.
Aaronaught

@Aaronaught Örneğin tüm verilere tek bir görünüm modelinde gerçekten ihtiyacı var. Belki ızgarası vardır ve farklı hizmetlerden farklı sütunlar gelir. Bunu kompozisyonla yapamazsınız.
Euphoric

@Euphoric: Aslında yapabilirsiniz kompozisyon ile bu çözmek, ama bu görünüm modeli seviyesinin altında yapılabilir. Bu sadece doğru soyutlamaları yaratma meselesidir. Bu durumda, kimlik listesini almak için ilk sorguyu işlemek için yalnızca bir hizmet ve kendi bilgileriyle açıklama ekleyen "zenginleştiriciler" dizisi / listesi / dizisi gerekir. Izgarayı kendi görünüm modeli haline getirin ve sorunu etkili bir şekilde iki bağımlılıkla çözdünüz ve test etmek son derece kolaydır.
Aaronaught

1

Bu konuda bir kitap yazabilirdim ... aslında öyleyim;)

Öncelikle, bir şeyler yapmak için evrensel olarak "doğru" bir yol yoktur. Başka faktörleri de dikkate almalısınız.

Hizmetlerinizin çok ince taneli olması mümkündür. Belirli bir Viewmodel veya hatta ilgili ViewModels kümesinin kullanacağı arabirimi sağlayan Hizmetleri Cephelerle Sarmak daha iyi bir çözüm olabilir.

Daha basit, hizmetleri tüm görünüm modellerinin kullandığı tek bir Cephe'ye sarmak olacaktır. Tabii ki bu potansiyel olarak ortalama senaryo için pek çok gereksiz fonksiyonla çok büyük bir arayüz olabilir. Ancak, sisteminizdeki her iletiyi işleyen bir ileti yönlendiricisinden farklı olmadığını söyleyebilirim.

Aslında, sonunda pek çok mimarinin evrim geçirdiğini gördüğüm, Olay Toplayıcı deseni gibi bir şeyin etrafına inşa edilmiş bir mesaj veri yolu. Test sınıfınız sadece EA ile bir dinleyici kaydettirdiği ve buna karşılık olarak uygun olayı başlattığı için test yapmak kolaydır. Ancak bu, büyümesi zaman alan ileri bir senaryodur. Ben birleştirici cephe ile başlayın ve oradan gidin diyorum.


Devasa bir servis cephesi, bir mesaj brokerinden çok farklıdır. Neredeyse bağımlılık spektrumunun tam karşı ucunda. Bu mimarinin ayırt edici özelliği, gönderenin alıcı hakkında hiçbir şey bilmemesidir ve çok sayıda alıcı (pub / sub veya multicast) olabilir. Belki de uzak bir protokol üzerinden sadece geleneksel bir hizmet sunan RPC tarzı "uzaktan" ile karıştırıyorsunuz ve gönderen hem fiziksel (son nokta adresi) hem de mantıksal olarak (dönüş değeri) alıcıya hala bağlı.
Aaronaught

Benzerlik, cephenin bir yönlendirici gibi davrandığı, arayan kişinin hangi servis / hizmetlerin çağrıyı işlediğini bilmediği gibi, bir mesaj gönderen bir mesajın kim tarafından işlendiğini bilmiyor.
Michael Brown

Evet, ama cephe o zaman bir Tanrı Nesnesi . Görünüm Modellerinin sahip olduğu tüm bağımlılıklara sahiptir, muhtemelen daha fazlası, çünkü birkaç kişi tarafından paylaşılacaktır. Aslında, ilk etapta çok çalıştığınız gevşek kuplajın faydalarını ortadan kaldırdınız, çünkü şimdi, bir şey mega cepheye dokunduğunda, hangi işlevselliğe gerçekten bağlı olduğuna dair hiçbir fikriniz yok. Cepheyi kullanan bir sınıf için birim testi yazma resmi. Cephe için bir alay yaratırsınız. Şimdi, hangi yöntemlerle alay ediyorsunuz? Kurulum kodunuz nasıl görünüyor?
Aaronaught

Bu, bir ileti aracısından çok farklıdır, çünkü aracı aynı zamanda ileti işleyicilerin uygulanması hakkında hiçbir şey bilmez . Kaputun altında IoC kullanır. Cephe, alıcılar hakkında her şeyi bilir, çünkü çağrıları onlara yönlendirmek zorundadır. Veriyolunun sıfır bağlantısı vardır; cephenin açık bir şekilde yüksek verimli bağlantıya sahiptir. Neredeyse her yerde değiştirdiğiniz her şey cepheyi de etkileyecektir.
Aaronaught

Sanırım buradaki karışıklığın bir kısmı - ve bunu çok fazla görüyorum - sadece bağımlılığın anlamıdır. Başka bir sınıfa bağlı bir sınıfınız varsa, ancak bu sınıfın 4 yöntemini çağırıyorsa, 1 değil 4 bağımlılığı vardır. Her şeyi bir cephenin arkasına koymak bağımlılık sayısını değiştirmez, sadece anlamalarını zorlaştırır .
Aaronaught

0

Neden ikisini birleştirmiyorsun?

Bir cephe oluşturun ve görünüm modellerinizin kullandığı tüm hizmetleri koyun. Daha sonra kötü S kelimesi olmadan tüm görünüm modelleriniz için tek bir cepheye sahip olabilirsiniz.

Veya yapıcı enjeksiyonu yerine özellik enjeksiyonu kullanabilirsiniz. Ama sonra, bunların düzgün bir şekilde enjekte edildiğinden emin olmanız gerekir.


Sözde-C # 'da bir örnek verdiyseniz, bu daha iyi bir yanıt olacaktır.
Robert Harvey
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.