2009-07-17 21 views
10

Eğer insanlar bunun ölümüne dövüldüğünü düşünürlerse önceden özür dilerim. Son birkaç saatimi SO'da çok sayıda mükemmel gönderiyi okumak ve okumakla geçirdim ama hala kafam karıştı.DDD, Deposu ve Enkapsülasyon

Benim karışıklığımın kaynağı DTO ve DDD ve depolar. POCO alanımdaki nesnelerin akıllılara sahip olmasını istiyorum ve bunları depolardan almak istiyorum. Ama bu işi yapmak için bazı kapsülleme kurallarını ihlal etmem gerekiyor gibi görünüyor ve DTO'ları başlarına döndürecek gibi görünüyor.

İşte basit bir örnek: Katalog uygulamasında, bir parça, bir dizi başka parça içeren bir paket olabilir. Bu nedenle, Part POCO'nun IEnumerable < Part> 'i döndüren' GetChildren() 'yöntemine sahip olması mantıklıdır. Dışarı çıkarken listeyle başka şeyler bile yapabilir.

Fakat bu liste nasıl çözümleniyor? Şimdi deposundan (doğru) yükleme bölümlerine ek olarak Katalogumda, tüketiciler, Ayrıca bazı Bölüm-kapsüllü bypass

interface IPartRepository : IRepository<Part> 
{ 
    // Part LoadByID(int id); comes from IRepository<Part> 
    IEnumerable<Part> GetChildren(Part part); 
} 

Ve

class Part 
{ 
    ... 
    public IEnumerable<Part> GetChildren() 
    { 
     // Might manipulate this list on the way out! 
     return partRepository.GetChildren(this); 
    } 
} 

: depo gibi görünüyor cevaptır GetChildren (bölüm) doğrudan arayarak mantık. Bu kötü değil mi?

Depoların POCO'lara hizmet etmesi gerektiğini, ancak DTO'ların 'katmanlar arasında' veri aktarımı için iyi olduğunu okudum. Birçok parça mülkiyeti hesaplanır - fiyatlar örneğin karmaşık fiyatlandırma kurallarına göre hesaplanır. Bir fiyat, bir depodan gelen bir DTO'da bile olmayacaktır - bu nedenle, fiyatlandırma verilerini bir web hizmetine geçirmenin, DTO'nun, Bölümü başka bir şekilde değil, Tüketimi tüketmesini gerektirmesi gibi görünüyor.

Bu zaten çok uzun sürüyor. Kafam nasıl çözüldü?

cevap

2

Bu sorunu çözen bir yaklaşım, mantığı çocuk bölümlerine taşımaktır - yani, sınıfın anlamlarını değiştirerek Part nesnelerinin, bir üst öğe ile ilişkilendirildiklerinde kendilerini dönüştürmekten sorumlu olmasını sağlayın. Bir Part fiyatı kendi üst Part bağlıdır eğer

Örneğin, fiyat (en azından) aşağıdaki zamanlarda belirlenebilir: inşaat üzerine

  • eğer bir ebeveyn Part (ve tüm diğer gerekli veriler) mevcuttur. Bir AttachToParent(Part parentPart) yönteminde veya bir olaya yanıt olarak, OnAttachedToParent(Part parentPart). İstemci kodu (yani, Price özelliğinin ilk erişiminde) gerektiğinde, gereksinim duyulduğunda (örn. Price özelliğinin ilk erişiminde).


Düzenleme: benim orijinal cevap (aşağıda) gerçekten DDD ruhu içinde değildi. Etki alanı nesneleri basit kapsayıcılar yapmakla ilgiliydi, birçok kişi tarafından düşünülen bir tasarım bir anti-desen (bkz. Anemic Domain Model).

Part ve IPartRepository arasında ek bir katman bu sorunu çözer (bunu IPartService arayacağım): IPartService içine GetChildren(part) taşımak ve daha sonra almak için istemci kod çağrısı IPartService yapmak, Part çıkarın Part nesneler ve çocukları ziyade doğrudan depoya isabet. Part sınıfının hala bir ChildParts (veya Children) özelliği vardır - yalnızca kendisini nasıl dolduracağını bilmez.

Açıkçası, bu ek maliyetler getiriyor - çoğu durumda ekstra iş mantığına ihtiyacınız yoksa, depo aramaları için yazma veya çok sayıda geçiş kodu oluşturabilirsin.

+0

İlginç. Fakat 'GetChildren (bölüm)' i IPartServis'e taşıyın ve onu parçadan kaldırın ve sonra 'Part sınıfının hala bir Childparts özelliği var.' Ya kısmen çocuklarına masaj yapması gerekiyorsa? – n8wrl

+1

Eğer masajı depodan aldığınızda hemen gerçekleşmesi gerekiyorsa, bu mantığı 'IPartService.GetChildren() 'içine koyardım. Çocuk bölümlerini isteğe bağlı olarak değiştirebilmeniz gerekiyorsa, 'IPartService.UpdateChildPartPrices (Part part)' gibi başka bir hizmet yöntemini kullanabilirsiniz. (Ya da her ikisi de - "UpdateChildPartPrices" öğesini "GetChildren" olarak adlandırırsınız.) –

+0

Zaman ayırdığınız için teşekkürler, Jeff! – n8wrl

0

Denklemin buradaki eksik kısmı, Parts nesnesinin davranışı ve toplamayla nasıl çalışmak istediğinizdir. Her bir yinelemenin Part'un her bir çocuğu üzerinde çalışmanız mı gerekiyor, yoksa sadece bir "kök" Part (yani ebeveynleri olmayanlar) ile çalışıyor musunuz ve çocuklar bir bütün olarak mı?

oldukça jenerik yazılan Parts olarak çocukların listesini içeren özellikle de alan adı modeli ifade olmaz, ama her çocuk koleksiyonu yapmak ve yinelemeli tembel yük olabilir gibi görünüyor bir Part agrega kök olmak. Ancak, sonsuz özyinelemenin mümkün olduğu yerlerde hala çok dikkatli olurdum.

İkinci endişeniz için, DTO'lar veri katmanları arasında veri aktarımı için olduğu kadar katmanlar arasında veri aktarımı için değildir.

Servis odaklı bir mimari kullanıyorsanız (web servislerinden bahsediyorsunuz, ancak herhangi bir SOA olabilir) çok kullanışlıdırlar. Servisleriniz depolarınızı sorgulayacak, herhangi bir ekstra çalışma yapacak ve daha sonra, talepte bulunan istemcilere geri göndermek için etki alanı nesnelerini düz DTO'larla eşleştirecektir. DTO'lar basit olmalı, serileştirme amacı ile özel mantık ve uygulama fonksiyonu içermemelidir.

Uygulamanızdaki etki alanı nesnelerini ve dışarıdaki DTO'ları kullanın.