domain model - अमीर बनाम एनीमिक डोमेन मॉडल




domain-model anemic-domain-model (6)

सबसे पहले, मैंने इस आलेख से उत्तर चिपकाया http://msdn.microsoft.com/en-gb/magazine/dn385704.aspx

चित्रा 1 एक एनीमिक डोमेन मॉडल दिखाता है, जो मूल रूप से गेटर्स और सेटर्स के साथ एक स्कीमा है।

Figure 1 Typical Anemic Domain Model Classes Look Like Database Tables

public class Customer : Person
{
  public Customer()
  {
    Orders = new List<Order>();
  }
  public ICollection<Order> Orders { get; set; }
  public string SalesPersonId { get; set; }
  public ShippingAddress ShippingAddress { get; set; }
}
public abstract class Person
{
  public int Id { get; set; }
  public string Title { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string CompanyName { get; set; }
  public string EmailAddress { get; set; }
  public string Phone { get; set; }
}

इस समृद्ध मॉडल में, केवल संपत्तियों को पढ़ने और लिखने के बजाय, ग्राहक की सार्वजनिक सतह स्पष्ट तरीकों से बना है।

Figure 2 A Customer Type That’s a Rich Domain Model, Not Simply Properties

public class Customer : Contact
{
  public Customer(string firstName, string lastName, string email)
  {
    FullName = new FullName(firstName, lastName);
    EmailAddress = email;
    Status = CustomerStatus.Silver;
  }
  internal Customer()
  {
  }
  public void UseBillingAddressForShippingAddress()
  {
    ShippingAddress = new Address(
      BillingAddress.Street1, BillingAddress.Street2,
      BillingAddress.City, BillingAddress.Region,
      BillingAddress.Country, BillingAddress.PostalCode);
  }
  public void CreateNewShippingAddress(string street1, string street2,
   string city, string region, string country, string postalCode)
  {
    ShippingAddress = new Address(
      street1,street2,
      city,region,
      country,postalCode)
  }
  public void CreateBillingInformation(string street1,string street2,
   string city,string region,string country, string postalCode,
   string creditcardNumber, string bankName)
  {
    BillingAddress = new Address      (street1,street2, city,region,country,postalCode );
    CreditCard = new CustomerCreditCard (bankName, creditcardNumber );
  }
  public void SetCustomerContactDetails
   (string email, string phone, string companyName)
  {
    EmailAddress = email;
    Phone = phone;
    CompanyName = companyName;
  }
  public string SalesPersonId { get; private set; }
  public CustomerStatus Status { get; private set; }
  public Address ShippingAddress { get; private set; }
  public Address BillingAddress { get; private set; }
  public CustomerCreditCard CreditCard { get; private set; }
}

मैं निर्णय ले रहा हूं कि क्या मुझे एनीमिक डोमेन मॉडल पर एक रिच डोमेन मॉडल का उपयोग करना चाहिए, और दोनों के अच्छे उदाहरण ढूंढना चाहिए।

मैं एक एनीमिक डोमेन मॉडल का उपयोग कर वेब अनुप्रयोगों का निर्माण कर रहा हूं, जो एक सेवा -> रिपोजिटरी -> स्टोरेज लेयर सिस्टम द्वारा समर्थित है, बीएल सत्यापन के लिए फ़्लुएंट वैलिडेशन का उपयोग करके, और मेरे सभी बीएल को सर्विस लेयर में डाल रहा है।

मैंने एरिक इवान की डीडीडी पुस्तक पढ़ी है, और वह (फाउलर और अन्य के साथ) लगता है कि एनीमिक डोमेन मॉडल एक विरोधी पैटर्न हैं।

इसलिए मैं वास्तव में इस समस्या में कुछ अंतर्दृष्टि प्राप्त करना चाहता था।

इसके अलावा मैं वास्तव में एक रिच डोमेन मॉडल के कुछ अच्छे (मूल) उदाहरणों की तलाश कर रहा हूं, और यह एनीमिक डोमेन मॉडल पर लाभ प्रदान करता है।


Bozhidar Bozhanov this ब्लॉग पोस्ट में एनीमिक मॉडल के पक्ष में बहस प्रतीत होता है।

वह सारांश प्रस्तुत करता है जो वह प्रस्तुत करता है:

  • डोमेन ऑब्जेक्ट्स वसंत (आईओसी) प्रबंधित नहीं होना चाहिए, उनके पास डीएओ या इंजेक्शन से जुड़े इंफ्रास्ट्रक्चर से संबंधित कुछ भी नहीं होना चाहिए

  • डोमेन ऑब्जेक्ट्स में डोमेन ऑब्जेक्ट्स होते हैं जो वे हाइबरनेट (या दृढ़ता तंत्र) द्वारा सेट पर निर्भर करते हैं।

  • डोमेन ऑब्जेक्ट्स व्यवसाय तर्क को निष्पादित करते हैं, क्योंकि डीडीडी का मूल विचार है, लेकिन इसमें डेटाबेस क्वेरीज या सीआरयूडी शामिल नहीं है - ऑब्जेक्ट की आंतरिक स्थिति पर केवल ऑपरेशन

  • डीटीओ की शायद ही कभी आवश्यकता होती है - ज्यादातर मामलों में डोमेन ऑब्जेक्ट्स डीटीओ स्वयं होते हैं (जो कुछ बॉयलरप्लेट कोड बचाता है)

  • सेवाएं सीआरयूडी संचालन करती हैं, ईमेल भेजती हैं, डोमेन ऑब्जेक्ट्स को समन्वयित करती हैं, एकाधिक डोमेन ऑब्जेक्ट्स के आधार पर रिपोर्ट जेनरेट करती हैं, क्वेरी निष्पादित करती हैं आदि।

  • सेवा (एप्लिकेशन) परत पतली नहीं है, लेकिन इसमें डोमेन नियमों के लिए आंतरिक नियम शामिल नहीं हैं

  • कोड पीढ़ी से बचा जाना चाहिए। कोड जनरेशन से छुटकारा पाने के लिए, कोड जनरेशन की आवश्यकता को दूर करने के लिए एब्स्ट्रक्शन, डिज़ाइन पैटर्न और DI का उपयोग किया जाना चाहिए।

अद्यतन करें

मैंने हाल ही में ADM+DDD आलेख को पढ़ा है जहां लेखक एक प्रकार के संकर दृष्टिकोण का पालन करने की वकालत करते हैं - डोमेन ऑब्जेक्ट्स पूरी तरह से अपने राज्य पर आधारित विभिन्न प्रश्नों का उत्तर दे सकते हैं (जो पूरी तरह से एनीमिक मॉडल के मामले में सेवा परत में किया जाएगा)


जब मैं मोनोलिथिक डेस्कटॉप ऐप्स लिखता था तो मैंने समृद्ध डोमेन मॉडल बनाए, जिनका निर्माण करने के लिए उपयोग किया जाता था।

अब मैं छोटे HTTP माइक्रोस्कोप लिखता हूं, एनीमिक डीटीओ समेत जितना संभव हो उतना छोटा कोड है।

मुझे लगता है कि डीडीडी और इस एनीमिक तर्क की तारीख मोनोलिथिक डेस्कटॉप या सर्वर एप युग से है। मुझे याद है कि युग और मैं इस बात से सहमत हूं कि एनीमिक मॉडल अजीब हैं। मैंने एक बड़ा मोनोलिथिक एफएक्स ट्रेडिंग ऐप बनाया और कोई मॉडल नहीं था, वास्तव में, यह भयानक था।

सूक्ष्मजीवों के साथ, उनके समृद्ध व्यवहार के साथ छोटी सेवाएं, एक डोमेन के भीतर तर्कसंगत मॉडल और समेकित हैं। इसलिए माइक्रोस्कोप कार्यान्वयन के लिए आगे डीडीडी की आवश्यकता नहीं हो सकती है। माइक्रोस्कोस एप्लिकेशन डोमेन हो सकता है।

एक आदेश माइक्रोस्कोप में बहुत कम फ़ंक्शन हो सकते हैं, जो विश्वसनीय संसाधनों के रूप में या SOAP या जो भी हो। आदेश microservice कोड बेहद सरल हो सकता है।

एक बड़ी अधिक मोनोलिथिक सिंगल (माइक्रो) सेवा, विशेष रूप से जो इसे रैम में मॉडल रखती है, डीडीडी से लाभान्वित हो सकती है।


मेरा दृष्टिकोण यह है:

एनीमिक डोमेन मॉडल = ऑब्जेक्ट्स में मैप किए गए डेटाबेस टेबल (केवल फ़ील्ड मान, कोई असली व्यवहार नहीं)

रिच डोमेन मॉडल = ऑब्जेक्ट्स का संग्रह जो व्यवहार का पर्दाफाश करता है

यदि आप एक साधारण सीआरयूडी एप्लीकेशन बनाना चाहते हैं, तो शायद क्लासिक एमवीसी ढांचे के साथ एक एनीमिक मॉडल पर्याप्त है। लेकिन अगर आप किसी प्रकार के तर्क को लागू करना चाहते हैं, तो एनीमिक मॉडल का मतलब है कि आप ऑब्जेक्ट उन्मुख प्रोग्रामिंग नहीं करेंगे।

* ध्यान दें कि ऑब्जेक्ट व्यवहार में दृढ़ता से कोई लेना देना नहीं है। डोमेन ऑब्जेक्ट्स के लिए एक अलग परत (डेटा मैपर, रिपोजिटरीज इत्यादि) ज़िम्मेदार है।


समृद्ध डोमेन कक्षाओं के लाभ में से एक यह है कि जब भी आप किसी भी परत में ऑब्जेक्ट का संदर्भ रखते हैं तो आप उनके व्यवहार (विधियों) को कॉल कर सकते हैं। साथ ही, आप छोटे और वितरित विधियों को लिखते हैं जो एक साथ सहयोग करते हैं। एनीमिक डोमेन कक्षाओं में, आप वसा प्रक्रियात्मक तरीकों (सेवा परत में) लिखते हैं जो आमतौर पर उपयोग के मामले द्वारा संचालित होते हैं। वे आमतौर पर समृद्ध डोमेन कक्षाओं की तुलना में कम रखरखाव योग्य होते हैं।

व्यवहार के साथ डोमेन कक्षाओं का एक उदाहरण:

class Order {

     String number

     List<OrderItem> items

     ItemList bonus

     Delivery delivery

     void addItem(Item item) { // add bonus if necessary }

     ItemList needToDeliver() { // items + bonus }

     void deliver() {
         delivery = new Delivery()
         delivery.items = needToDeliver()
     }

}

विधि की आवश्यकता है needToDeliver() बोनस सहित वितरित करने की आवश्यकता वाले आइटम की सूची वापस कर देगा। इसे कक्षा के अंदर, किसी अन्य संबंधित वर्ग से, या किसी अन्य परत से कहा जा सकता है। उदाहरण के लिए, यदि आप Order देखने के लिए पास करते हैं, तो आप Order जारी रखने के लिए सहेजें बटन पर क्लिक करने से पहले उपयोगकर्ता द्वारा पुष्टि की जाने वाली वस्तुओं की सूची प्रदर्शित करने के लिए चयनित Order की needToDeliver()

टिप्पणी करने का जवाब

इस प्रकार मैं डोमेन वर्ग को नियंत्रक से उपयोग करता हूं:

def save = {
   Order order = new Order()
   order.addItem(new Item())
   order.addItem(new Item())
   repository.create(order)
}

Order और इसकी LineItem का निर्माण एक लेनदेन में है। यदि LineItem में से LineItem भी नहीं बनाया जा सकता है, तो कोई Order नहीं बनाया जाएगा।

मेरे पास ऐसी विधि है जो एक लेनदेन का प्रतिनिधित्व करती है, जैसे कि:

def deliver = {
   Order order = repository.findOrderByNumber('ORDER-1')
   order.deliver()       
   // save order if necessary
}

deliver() अंदर कुछ भी एक एकल लेनदेन के रूप में निष्पादित किया जाएगा। अगर मुझे एक ही लेनदेन में कई असंबंधित तरीकों को निष्पादित करने की आवश्यकता है, तो मैं एक सेवा कक्षा तैयार करूंगा।

आलसी लोडिंग अपवाद से बचने के लिए, मैं जेपीए 2.1 नाम इकाई इकाई का उपयोग करता हूं। उदाहरण के लिए, डिलीवरी स्क्रीन के लिए नियंत्रक में, मैं delivery विशेषता लोड करने के लिए विधि बना सकता हूं और bonus अनदेखा कर सकता हूं, जैसे repository.findOrderByNumberFetchDelivery() । बोनस स्क्रीन में, मैं एक और तरीका कहता हूं जो bonus विशेषता लोड करता है और delivery अनदेखा करता delivery , जैसे repository.findOrderByNumberFetchBonus() । इसके लिए डिस्प्ले की आवश्यकता है क्योंकि मैं अभी भी बोनस स्क्रीन के अंदर deliver() को कॉल नहीं कर सकता।


अंतर यह है कि एक एनीमिक मॉडल तर्क से डेटा को अलग करता है। तर्क अक्सर **Service नामक कक्षाओं में रखा जाता है, **Util , **Manager , **Helper और इसी तरह। ये वर्ग डेटा व्याख्या तर्क लागू करते हैं और इसलिए डेटा मॉडल को तर्क के रूप में लेते हैं। उदाहरण के लिए

public BigDecimal calculateTotal(Order order){
...
}

जबकि समृद्ध डोमेन दृष्टिकोण समृद्ध डोमेन मॉडल में डेटा व्याख्या तर्क डालकर इसे उलट देता है। इस प्रकार यह तर्क और डेटा को एक साथ रखता है और एक समृद्ध डोमेन मॉडल इस तरह दिखेगा:

order.getTotal();

इसका ऑब्जेक्ट स्थिरता पर बड़ा प्रभाव पड़ता है। चूंकि डेटा व्याख्या तर्क डेटा को लपेटता है (डेटा केवल ऑब्जेक्ट विधियों के माध्यम से पहुंचा जा सकता है) विधियां अन्य डेटा के राज्य परिवर्तनों पर प्रतिक्रिया दे सकती हैं -> यही वह है जिसे हम व्यवहार कहते हैं।

एक एनीमिक मॉडल में डेटा मॉडल गारंटी नहीं दे सकते कि वे एक कानूनी स्थिति में हैं जबकि एक समृद्ध डोमेन मॉडल में वे कर सकते हैं। एक समृद्ध डोमेन मॉडल ओओ सिद्धांतों को लागू करता है जैसे encapsulation, जानकारी छिपाने और डेटा और तर्क लाने के साथ-साथ एक एनीमिक मॉडल एक ओओ परिप्रेक्ष्य से एक विरोधी पैटर्न है।

एक गहन अंतर्दृष्टि के लिए मेरे ब्लॉग https://www.link-intersystems.com/blog/2011/10/01/anemic-vs-rich-domain-models/ पर एक नज़र डालें