Rich vs Anemic Domain Model [ปิด]


99

ฉันกำลังตัดสินใจว่าควรใช้ Rich Domain Model กับ Anemic Domain Model หรือไม่และกำลังมองหาตัวอย่างที่ดีของทั้งสอง

ฉันได้สร้างเว็บแอปพลิเคชันโดยใช้ Anemic Domain Model ซึ่งได้รับการสนับสนุนโดยService -> Repository -> Storage Layer System โดยใช้FluentValidationสำหรับการตรวจสอบ BL และวาง BL ทั้งหมดของฉันในชั้น Service

ฉันได้อ่านหนังสือ DDD ของ Eric Evan และเขา (พร้อมกับ Fowler และคนอื่น ๆ ) ดูเหมือนว่า Anemic Domain Models จะต่อต้านรูปแบบ

ดังนั้นฉันแค่อยากได้ข้อมูลเชิงลึกเกี่ยวกับปัญหานี้

นอกจากนี้ฉันกำลังมองหาตัวอย่างที่ดี (พื้นฐาน) ของ Rich Domain Model และประโยชน์ที่ได้รับจาก Anemic Domain Model ที่มีให้


คุณอาจต้องการดูบล็อก
Japheth Ongeri - inkalimeva

14
DDD> ADM , ADM> DDD , DDD> ADM , ADM> DDD , ADM + DDD ... DDD / ADM หรือจะไม่ตกลงเกี่ยวกับการออกแบบซอฟต์แวร์ได้อย่างไร !
sp00m

นี่คือตัวอย่างของวิธีหลีกเลี่ยงโมเดลโดเมนโลหิตจาง: medium.com/@wrong.about/…
Vadim Samokhin

11
เป็นเรื่องตลกที่คำถามนี้สามารถตอบได้ด้วยลิงก์เดียวไปยังโครงการในโลกแห่งความเป็นจริงที่ได้รับทุนจากองค์กรจริง หลังจาก 5 ปีไม่มีคำตอบที่ดี IMO พูดคุยราคาถูก แสดงรหัส
Mateusz Stefek

คำตอบ:


59

ความแตกต่างคือแบบจำลองโลหิตจางแยกตรรกะออกจากข้อมูล ตรรกะมักจะวางไว้ในชั้นเรียนชื่อ**Service, **Util, **Manager, **Helperและอื่น ๆ คลาสเหล่านี้ใช้ตรรกะการตีความข้อมูลดังนั้นจึงใช้โมเดลข้อมูลเป็นอาร์กิวเมนต์ เช่น

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

ในขณะที่วิธีการของโดเมนที่สมบูรณ์จะกลับตรงกันข้ามโดยวางตรรกะการตีความข้อมูลลงในแบบจำลองโดเมนที่สมบูรณ์ ดังนั้นจึงรวมตรรกะและข้อมูลเข้าด้วยกันและโมเดลโดเมนที่สมบูรณ์จะมีลักษณะดังนี้:

order.getTotal();

สิ่งนี้มีผลอย่างมากต่อความสอดคล้องของวัตถุ เนื่องจากตรรกะการตีความข้อมูลจะห่อหุ้มข้อมูลไว้ (ข้อมูลสามารถเข้าถึงได้โดยวิธีออบเจ็กต์เท่านั้น) เมธอดจึงสามารถตอบสนองต่อการเปลี่ยนแปลงสถานะของข้อมูลอื่น -> นี่คือสิ่งที่เราเรียกว่าพฤติกรรม

ในแบบจำลองภาวะโลหิตจางแบบจำลองข้อมูลไม่สามารถรับประกันได้ว่าอยู่ในสถานะทางกฎหมายในขณะที่อยู่ในรูปแบบโดเมนที่สมบูรณ์ แบบจำลองโดเมนที่สมบูรณ์ใช้หลักการ OO เช่นการห่อหุ้มการซ่อนข้อมูลและการนำข้อมูลและตรรกะเข้าด้วยกันดังนั้นแบบจำลองภาวะโลหิตจางจึงเป็นรูปแบบการต่อต้านจากมุมมองของ OO

สำหรับข้อมูลเชิงลึกเพิ่มเติมโปรดดูที่บล็อกของฉันhttps://www.link-intersystems.com/blog/2011/10/01/anemic-vs-rich-domain-models/


15
สมมติว่าการคำนวณราคารวมของคำสั่งซื้อนั้นเกี่ยวข้องกับ: 1) การใช้ส่วนลดซึ่งขึ้นอยู่กับลูกค้าที่เป็นสมาชิกของโปรแกรมความภักดีหลายโปรแกรมที่เป็นไปได้ 2) การใช้ส่วนลดสำหรับคำสั่งซื้อที่มีกลุ่มสินค้าเฉพาะร่วมกันขึ้นอยู่กับแคมเปญการตลาดปัจจุบันที่ดำเนินการโดยร้านค้า 3) การคำนวณภาษีโดยที่จำนวนภาษีขึ้นอยู่กับแต่ละรายการเฉพาะของคำสั่งซื้อ ในความคิดของคุณตรรกะทั้งหมดนี้จะอยู่ที่ไหน? คุณช่วยยกตัวอย่างรหัสหลอกง่ายๆได้ไหม ขอบคุณ!
Nik

4
@Nik ในรูปแบบที่สมบูรณ์คำสั่งซื้อจะมีการอ้างอิงถึงวัตถุของลูกค้าและวัตถุของลูกค้าจะมีการอ้างอิงถึงโปรแกรมความภักดี ดังนั้นคำสั่งซื้อจะสามารถเข้าถึงข้อมูลทั้งหมดที่จำเป็นโดยไม่จำเป็นต้องมีการอ้างอิงที่ชัดเจนถึงสิ่งต่างๆเช่นบริการและที่เก็บเพื่อดึงข้อมูลนั้น อย่างไรก็ตามดูเหมือนเป็นเรื่องง่ายที่จะพบในกรณีที่มีการอ้างอิงวัฏจักรเกิดขึ้น เช่นการอ้างอิงคำสั่งซื้อลูกค้าลูกค้ามีรายการคำสั่งซื้อทั้งหมดฉันคิดว่านี่อาจเป็นสาเหตุบางส่วนว่าทำไมคนถึงชอบ Anemic ในตอนนี้
ขยี้

3
@crush วิธีที่คุณอธิบายใช้ได้ดีจริงๆ มีอย่างหนึ่งที่จับได้ ดูเหมือนว่าเราจะจัดเก็บเอนทิตีไว้ในฐานข้อมูล ดังนั้นในการคำนวณยอดรวมของคำสั่งซื้อเราต้องดึงคำสั่งซื้อลูกค้าโปรแกรมความภักดีแคมเปญการตลาดตารางภาษีจากฐานข้อมูล นอกจากนี้ลูกค้ายังมีชุดคำสั่งซื้อโปรแกรมความภักดีมีกลุ่มลูกค้าและอื่น ๆ หากเราดึงข้อมูลทั้งหมดนี้มาอย่างไร้เดียงสาเราจะโหลด DB ทั้งหมดใน RAM สิ่งนี้ใช้ไม่ได้แน่นอนดังนั้นเราจึงใช้การโหลดเฉพาะข้อมูลที่เกี่ยวข้องจาก DB ... 1/2
Nik

3
@Nik "ถ้าเราดึงข้อมูลทั้งหมดนี้มาโดยกำเนิดเราจะโหลด DB ทั้งหมดใน RAM" นั่นเป็นข้อเสียเปรียบหลักประการหนึ่งของโมเดลที่ร่ำรวยในความคิดของฉันเช่นกัน รูปแบบที่สมบูรณ์เป็นสิ่งที่ดีจนกว่าโดเมนของคุณจะมีขนาดใหญ่และซับซ้อนจากนั้นคุณก็เริ่มก้าวข้ามข้อ จำกัด ของโครงสร้างพื้นฐาน นั่นคือจุดที่ Lazy-load ORM สามารถเข้ามาช่วยได้ ค้นหาสิ่งที่ดีและคุณสามารถเก็บโมเดลที่สมบูรณ์ไว้ได้ในขณะที่ไม่โหลดฐานข้อมูลทั้งหมดลงในหน่วยความจำเมื่อคุณต้องการเพียง 1/20 ของมัน ที่กล่าวว่าฉันมักจะใช้ Anemic Model กับ CQRS ด้วยตัวเองหลังจากผ่านไปหลายปีระหว่างโรคโลหิตจางและคนรวย
ปิ๊ง

2
สิ่งที่ควรพิจารณาอีกประการหนึ่งคือตรรกะของโดเมนธุรกิจของคุณอยู่ที่ใด นักพัฒนาจำนวนมากขึ้นเรื่อย ๆ เปลี่ยนมันออกจากฐานข้อมูลและไปยังแอปพลิเคชันที่อยู่ในความคิดของฉัน แต่ถ้าคุณติดอยู่ในสถานการณ์ที่ บริษัท ของคุณต้องการให้ตรรกะทางธุรกิจอยู่ในชั้นฐานข้อมูล (ขั้นตอนที่จัดเก็บไว้) คุณแทบจะไม่ได้รับประโยชน์จากการเพิ่มตรรกะนั้นในแบบจำลองโดเมนที่สมบูรณ์ ในความเป็นจริงคุณสามารถตั้งค่าตัวเองเพื่อ
สนใจ

54

Bozhidar Bozhanov ดูเหมือนว่าจะยืนยันในความโปรดปรานของรูปแบบที่เป็นโรคโลหิตจางในนี้โพสต์บล็อก

นี่คือบทสรุปที่เขานำเสนอ:

  • ออบเจ็กต์โดเมนไม่ควรได้รับการจัดการแบบสปริง (IoC) ไม่ควรมี DAO หรือสิ่งที่เกี่ยวข้องกับโครงสร้างพื้นฐานแทรกอยู่

  • อ็อบเจ็กต์โดเมนมีอ็อบเจ็กต์โดเมนที่ขึ้นอยู่กับการกำหนดโดยไฮเบอร์เนต (หรือกลไกการคงอยู่)

  • อ็อบเจ็กต์โดเมนดำเนินการตรรกะทางธุรกิจตามแนวคิดหลักของ DDD คือ แต่สิ่งนี้ไม่รวมเคียวรีฐานข้อมูลหรือ CRUD - ดำเนินการเฉพาะกับสถานะภายในของอ็อบเจ็กต์เท่านั้น

  • แทบไม่จำเป็นต้องมี DTO - วัตถุโดเมนคือ DTO เองในกรณีส่วนใหญ่ (ซึ่งบันทึกรหัสสำเร็จรูปบางส่วน)

  • บริการดำเนินการ CRUD ส่งอีเมลประสานงานวัตถุโดเมนสร้างรายงานตามออบเจ็กต์โดเมนหลายรายการดำเนินการสืบค้น ฯลฯ

  • ชั้นบริการ (แอปพลิเคชัน) ไม่ได้บางขนาดนั้น แต่ไม่รวมกฎทางธุรกิจที่อยู่ภายในวัตถุโดเมน

  • ควรหลีกเลี่ยงการสร้างรหัส ควรใช้ Abstraction รูปแบบการออกแบบและ DI เพื่อเอาชนะความต้องการในการสร้างรหัสและท้ายที่สุด - เพื่อกำจัดการทำซ้ำรหัส

อัปเดต

ฉันเพิ่งอ่านนี้บทความที่สนับสนุนผู้เขียนต่อไปนี้เรียงลำดับของวิธีการไฮบริด - วัตถุโดเมนสามารถตอบคำถามต่างๆตาม แต่ในรัฐของพวกเขา (ซึ่งในกรณีของโรคโลหิตจางรุ่นโดยสิ้นเชิงอาจจะทำได้ในชั้นบริการ)


11
ฉันไม่สามารถแยกจากบทความนั้นได้ว่า Bozho ดูเหมือนจะโต้แย้งเกี่ยวกับรูปแบบโดเมนโลหิตจาง บริการ (Application) ชั้นไม่ว่าจะบาง แต่ไม่รวมถึงกฎเกณฑ์ทางธุรกิจที่มีอยู่ภายในวัตถุโดเมน สิ่งที่ฉันเข้าใจคืออ็อบเจ็กต์โดเมนควรมีตรรกะทางธุรกิจที่อยู่ภายใน แต่ไม่ควรมีตรรกะโครงสร้างพื้นฐานอื่น ๆ วิธีนี้ดูเหมือนจะไม่ใช่รูปแบบโดเมนโลหิตจางสำหรับฉันเลย
Utku

8
นอกจากนี้: วัตถุโดเมนดำเนินการตรรกะทางธุรกิจที่เป็นความคิดหลักของ DDD แต่นี้ไม่รวมถึงการสืบค้นฐานข้อมูลหรือ CRUD - การดำเนินงานเฉพาะในรัฐภายในของวัตถุ ข้อความเหล่านี้ดูเหมือนจะไม่สนับสนุนรูปแบบโดเมนโลหิตจางเลย พวกเขาระบุเพียงว่าตรรกะของโครงสร้างพื้นฐานไม่ควรใช้ร่วมกับวัตถุโดเมน อย่างน้อยนั่นคือสิ่งที่ฉันเข้าใจ
Utku

@Utku ในมุมมองของฉันดูเหมือนค่อนข้างชัดเจนว่า Bozho สนับสนุนการผสมระหว่างสองรุ่นซึ่งเป็นไฮบริดที่ฉันจะบอกว่าใกล้เคียงกับแบบจำลองโรคโลหิตจางมากกว่าแบบจำลองที่ร่ำรวย
geoand

41

มุมมองของฉันคือ:

แบบจำลองโดเมน Anemic = ตารางฐานข้อมูลที่แมปกับวัตถุ (เฉพาะค่าฟิลด์ไม่มีพฤติกรรมจริง)

แบบจำลองโดเมนที่สมบูรณ์ = ชุดของวัตถุที่แสดงพฤติกรรม

หากคุณต้องการสร้างแอปพลิเคชั่น CRUD แบบง่ายๆบางทีโมเดลโลหิตจางที่มีเฟรมเวิร์ก MVC แบบคลาสสิกก็เพียงพอแล้ว แต่ถ้าคุณต้องการใช้ตรรกะบางประเภทแบบจำลองภาวะโลหิตจางหมายความว่าคุณจะไม่ทำการเขียนโปรแกรมเชิงวัตถุ

* โปรดทราบว่าพฤติกรรมของวัตถุไม่เกี่ยวข้องกับการคงอยู่ เลเยอร์อื่น (Data Mappers, Repositories ฯลฯ ) มีหน้าที่รับผิดชอบต่อวัตถุโดเมน


5
ขออภัยในความไม่รู้ของฉัน แต่โมเดลโดเมนที่สมบูรณ์จะทำตามหลักการของ SOLID ได้อย่างไรถ้าคุณใส่ตรรกะที่เกี่ยวข้องกับเอนทิตีทั้งหมดในคลาส สิ่งนี้ละเมิดหลักการของ SOLID ซึ่งเป็น 'S' ที่ย่อมาจาก single responsability ที่กล่าวว่าชั้นเรียนควรทำเพียงสิ่งเดียวและทำให้ถูกต้อง
redigaffi

6
@redigaffi ขึ้นอยู่กับว่าคุณกำหนด "สิ่งหนึ่ง" อย่างไร พิจารณาระดับที่มีสองคุณสมบัติและสองวิธี: x, y, และsum differenceนั่นคือสี่ประการ หรือคุณอาจโต้แย้งว่ามันคือการบวกและการลบ (สองสิ่ง) หรือคุณอาจโต้แย้งว่ามันเป็นคณิตศาสตร์ (อย่างหนึ่ง) มีบล็อกโพสต์มากมายเกี่ยวกับวิธีการหาจุดสมดุลในการใช้ SRP นี่คือhackernoon.com/…
Rainbolt

2
ใน DDD ความสามารถในการตอบสนองเดียวหมายถึงคลาส / โมเดลสามารถจัดการสถานะของตัวเองได้โดยไม่ก่อให้เกิดผลข้างเคียงใด ๆ กับส่วนที่เหลือของระบบโดยรวม คำจำกัดความอื่นใดก็ส่งผลให้เกิดการถกเถียงทางปรัชญาที่น่าเบื่อหน่ายในประสบการณ์ของฉัน
ZombieTfk

12

ก่อนอื่นฉันคัดลอกคำตอบจากบทความนี้ http://msdn.microsoft.com/en-gb/magazine/dn385704.aspx

รูปที่ 1 แสดง Anemic Domain Model ซึ่งโดยพื้นฐานแล้วเป็น schema ที่มี getters และ setters

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; }
}

2
มีปัญหากับเมธอดที่สร้างอ็อบเจ็กต์และกำหนดคุณสมบัติกับอ็อบเจ็กต์ที่สร้างขึ้นใหม่ ทำให้โค้ดขยายและยืดหยุ่นน้อยลง 1) จะเกิดอะไรขึ้นหากผู้ใช้รหัสไม่ต้องการสร้างAddressแต่ExtendedAddressสืบทอดมาAddressพร้อมคุณสมบัติเพิ่มเติมหลายประการ 2) หรือเปลี่ยนCustomerCreditCardพารามิเตอร์ตัวสร้างที่จะใช้BankIDแทนBankName?
Lightman

การสร้างที่อยู่ต้องใช้บริการเพิ่มเติมนอกเหนือจากสิ่งที่เป็นส่วนประกอบของวัตถุ? คุณเหลือวิธีการฉีดเพื่อรับบริการเหล่านั้น ถ้าบริการเยอะ ๆ ล่ะ?
ขยี้

8

ประโยชน์อย่างหนึ่งของคลาสโดเมนที่สมบูรณ์คือคุณสามารถเรียกพฤติกรรม (วิธีการ) ของพวกเขาได้ทุกครั้งที่คุณมีการอ้างอิงถึงวัตถุในเลเยอร์ใด ๆ นอกจากนี้คุณมักจะเขียนวิธีการเล็ก ๆ และกระจายที่ทำงานร่วมกัน ในคลาสโดเมน anemic คุณมักจะเขียน fat Procedural method (ใน service layer) ซึ่งมักจะมาจาก use case โดยปกติจะมีการบำรุงรักษาน้อยกว่าเมื่อเทียบกับคลาสโดเมนที่สมบูรณ์

ตัวอย่างคลาสโดเมนที่มีพฤติกรรม:

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การดูแล้วคุณสามารถใช้needToDeliver()ในการเลือกOrderที่จะแสดงรายการของรายการที่จะได้รับการยืนยันจากผู้ใช้ก่อนที่พวกเขาคลิกที่ปุ่มบันทึกจะยังคงมีอยู่Order

การตอบกลับความคิดเห็น

นี่คือวิธีที่ฉันใช้คลาสโดเมนจากคอนโทรลเลอร์:

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

การสร้างOrderและมันLineItemอยู่ในธุรกรรมเดียว หากLineItemไม่สามารถสร้างอย่างใดอย่างหนึ่งได้จะไม่มีการOrderสร้าง

ฉันมักจะมีวิธีการที่แสดงถึงธุรกรรมเดียวเช่น:

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

ทุกสิ่งที่อยู่ภายในdeliver()จะถูกดำเนินการเป็นธุรกรรมเดียว หากฉันต้องการดำเนินการหลายวิธีที่ไม่เกี่ยวข้องในธุรกรรมเดียวฉันจะสร้างคลาสบริการ

เพื่อหลีกเลี่ยงข้อยกเว้นในการโหลดแบบขี้เกียจฉันใช้กราฟเอนทิตีที่มีชื่อ JPA 2.1 ตัวอย่างเช่นในตัวควบคุมสำหรับหน้าจอการจัดส่งฉันสามารถสร้างวิธีการโหลดdeliveryแอตทริบิวต์และละเว้นbonusเช่นrepository.findOrderByNumberFetchDelivery(). ในหน้าจอโบนัสฉันเรียกวิธีอื่นที่โหลดbonusแอตทริบิวต์และละเว้นdeliveryเช่นrepository.findOrderByNumberFetchBonus(). สิ่งนี้ต้องมีการคาดหวังเนื่องจากฉันยังไม่สามารถโทรเข้าdeliver()ในหน้าจอโบนัสได้


1
ขอบเขตธุรกรรมเป็นอย่างไร?
kboom

5
ลักษณะการทำงานของโมเดลโดเมนไม่ควรมีตรรกะการคงอยู่ (รวมถึงธุรกรรม) ควรทดสอบได้ (ในการทดสอบหน่วย) โดยไม่ต้องเชื่อมต่อกับฐานข้อมูล ขอบเขตการทำธุรกรรมเป็นความรับผิดชอบของชั้นบริการหรือชั้นการคงอยู่
jocki

1
แล้วขี้เกียจโหลดล่ะ
kboom

เมื่อคุณสร้างอินสแตนซ์ของคลาสโดเมนในการทดสอบหน่วยจะไม่อยู่ในสถานะที่มีการจัดการเนื่องจากเป็นวัตถุธรรมดา พฤติกรรมทั้งหมดสามารถทดสอบได้อย่างเหมาะสม
jocki

และจะเกิดอะไรขึ้นเมื่อคุณคาดหวังว่าวัตถุโดเมนจากชั้นบริการ ไม่มีการจัดการแล้วหรือ
kboom

8

เมื่อฉันเคยเขียนแอปเดสก์ท็อปเสาหินฉันสร้างแบบจำลองโดเมนที่หลากหลายเพื่อใช้ในการสร้างมัน

ตอนนี้ฉันเขียนไมโครเซอร์วิส HTTP เล็ก ๆ มีโค้ดน้อยที่สุดเท่าที่จะเป็นไปได้รวมถึง DTO ที่เป็นโรคโลหิตจาง

ฉันคิดว่า DDD และอาร์กิวเมนต์ anemic นี้เกิดขึ้นจากยุคแอปเดสก์ท็อปหรือเซิร์ฟเวอร์เสาหิน ฉันจำยุคนั้นได้และฉันยอมรับว่าแบบจำลองโรคโลหิตจางเป็นเรื่องแปลก ฉันสร้างแอพซื้อขาย FX เสาหินขนาดใหญ่และไม่มีโมเดลจริงๆมันแย่มาก

ด้วยบริการขนาดเล็กบริการขนาดเล็กที่มีลักษณะการทำงานที่สมบูรณ์เป็นเนื้อหาแบบจำลองที่ประกอบได้และการรวมภายในโดเมน ดังนั้นการติดตั้ง microservice เองอาจไม่จำเป็นต้องใช้ DDD เพิ่มเติม แอปพลิเคชัน microservice อาจเป็นโดเมน

ไมโครเซอร์วิสคำสั่งซื้ออาจมีฟังก์ชันน้อยมากโดยแสดงเป็นทรัพยากรที่เหลืออยู่หรือผ่านทาง SOAP หรืออะไรก็ตาม รหัสไมโครเซอร์วิสของคำสั่งซื้ออาจจะง่ายมาก

บริการเดี่ยว (ไมโคร) เสาหินที่ใหญ่ขึ้นโดยเฉพาะอย่างยิ่งบริการที่คงรูปแบบไว้ใน RAM อาจได้รับประโยชน์จาก DDD


คุณมีตัวอย่างโค้ดสำหรับไมโครเซอร์วิส HTTP ที่แสดงถึงสถานะปัจจุบันของคุณหรือไม่ ไม่ได้ขอให้คุณเขียนอะไรเลยเพียงแค่แชร์ลิงก์หากคุณมีสิ่งที่คุณสามารถชี้ไปได้ ขอบคุณ.
Casey Plummer

3

ฉันคิดว่าต้นตอของปัญหาอยู่ที่การแบ่งขั้วเท็จ เป็นไปได้อย่างไรที่จะแยก 2 รุ่นนี้ออกมาคือรวยและ "โรคโลหิตจาง" และนำมาเปรียบเทียบกัน? ฉันคิดว่ามันเป็นไปได้เฉพาะในกรณีที่คุณมีความคิดที่ไม่ถูกต้องเกี่ยวกับสิ่งที่อยู่ในชั้นเรียน ฉันไม่แน่ใจ แต่ฉันคิดว่าฉันพบในวิดีโอ Bozhidar Bozhanov ใน Youtube คลาสไม่ใช่ data + method สำหรับข้อมูลนี้ เป็นความเข้าใจที่ไม่ถูกต้องโดยสิ้นเชิงซึ่งนำไปสู่การแบ่งชั้นเรียนออกเป็นสองประเภท: ข้อมูลเท่านั้นดังนั้นรูปแบบโลหิตจางและข้อมูล + วิธีการ - แบบจำลองที่สมบูรณ์ (เพื่อให้ถูกต้องมากขึ้นมีหมวดที่ 3: วิธีการเท่านั้น)

ความจริงก็คือว่าชั้นเป็นแนวคิดในรูปแบบ ontological บางคำนิยามคำ, ความคิด, มันเป็นDENOTAT และความเข้าใจนี้จะกำจัดการแบ่งขั้วที่ผิดพลาด: คุณไม่สามารถมีเฉพาะ anemic model หรือ rich model เท่านั้นเนื่องจากหมายความว่าโมเดลของคุณไม่เพียงพอไม่เกี่ยวข้องกับความเป็นจริง: แนวคิดบางอย่างมีข้อมูลเท่านั้นบางส่วนมีวิธีการเท่านั้นบางส่วน ของพวกเขาผสม เนื่องจากเราพยายามอธิบายในกรณีนี้บางประเภทชุดวัตถุความสัมพันธ์แนวคิดกับคลาสและอย่างที่เราทราบแนวคิดบางอย่างเป็นกระบวนการเท่านั้น (วิธีการ) บางส่วนเป็นชุดของคุณลักษณะเท่านั้น (ข้อมูล) บางส่วน พวกเขามีความสัมพันธ์กับคุณลักษณะ (ผสม)

ฉันคิดว่าแอปพลิเคชั่นที่เพียงพอควรมีคลาสทุกประเภทและเพื่อหลีกเลี่ยงการ จำกัด ตัวเองโดยคลั่งไคล้เพียงรุ่นเดียว ไม่ว่าตรรกะจะเป็นตัวแทนอย่างไร: ด้วยรหัสหรือด้วยวัตถุข้อมูลที่ตีความได้ (เช่นFree Monads ) อย่างไรก็ตามเราควรมีคลาส (แนวคิด denotats) ที่แสดงถึงกระบวนการตรรกะความสัมพันธ์คุณลักษณะคุณลักษณะข้อมูล ฯลฯ และไม่ เพื่อพยายามหลีกเลี่ยงบางส่วนหรือลดทั้งหมดให้เหลือเพียงประเภทเดียวเท่านั้น

ดังนั้นเราสามารถแยกลอจิกไปยังคลาสอื่นและทิ้งข้อมูลไว้ในคลาสเดิมได้ แต่ก็ไม่สมเหตุสมผลเพราะแนวคิดบางอย่างอาจรวมถึงคุณลักษณะและความสัมพันธ์ / กระบวนการ / วิธีการและการแยกออกจากกันจะทำซ้ำแนวคิดภายใต้ 2 ชื่อซึ่งสามารถเป็นได้ ลดลงเป็นรูปแบบ: "OBJECT-Attributes" และ "OBJECT-Logic" เป็นภาษาขั้นตอนและการใช้งานที่ดีเนื่องจากข้อ จำกัดของพวกเขาแต่เป็นการหักห้ามใจตัวเองมากเกินไปสำหรับภาษาที่ช่วยให้คุณสามารถอธิบายแนวคิดได้ทุกประเภท


1

แบบจำลองโดเมน Anemic มีความสำคัญต่อ ORM และการโอนย้ายผ่านเครือข่ายได้ง่าย (เลือดของแอปพลิเคชันเชิงพาณิชย์ทั้งหมด) แต่ OO มีความสำคัญมากสำหรับการห่อหุ้มและทำให้ส่วน 'ธุรกรรม / การจัดการ' ของโค้ดของคุณง่ายขึ้น

ดังนั้นสิ่งที่สำคัญคือความสามารถในการระบุและเปลี่ยนจากโลกหนึ่งไปสู่อีกโลกหนึ่ง

ตั้งชื่อโมเดล Anemic เช่น AnemicUser หรือ UserDAO เป็นต้นเพื่อให้นักพัฒนาทราบว่ามีคลาสที่ดีกว่าให้ใช้จากนั้นมีตัวสร้างที่เหมาะสมสำหรับคลาส Anemic ที่ไม่มี

User(AnemicUser au)

และวิธีอะแด็ปเตอร์เพื่อสร้างคลาส anemic สำหรับการขนส่ง / การคงอยู่

User::ToAnemicUser() 

มุ่งที่จะใช้ผู้ใช้ Anemic ที่ไม่มีใครอยู่ในทุกที่นอกการขนส่ง / การคงอยู่


-1

นี่คือตัวอย่างที่อาจช่วยได้:

โลหิตจาง

class Box
{
    public int Height { get; set; }
    public int Width { get; set; }
}

ไม่เป็นโรคโลหิตจาง

class Box
{
    public int Height { get; private set; }
    public int Width { get; private set; }

    public Box(int height, int width)
    {
        if (height <= 0) {
            throw new ArgumentOutOfRangeException(nameof(height));
        }
        if (width <= 0) {
            throw new ArgumentOutOfRangeException(nameof(width));
        }
        Height = height;
        Width = width;
    }

    public int area()
    {
       return Height * Width;
    }
}

ดูเหมือนว่าสามารถแปลงเป็น ValueObject เทียบกับเอนทิตีได้
code5

เพียงแค่คัดลอกวางจาก Wikipedia โดยไม่มีคำอธิบายใด ๆ
wst

ใครเขียนเร็วกว่ากัน? @wst
Alireza Rahmani Khalili

@AlirezaRahmaniKhalili ตามประวัติ Wikipedia พวกเขามาก่อน ... เว้นแต่ฉันไม่เข้าใจคำถามของคุณ
wst

-1

แนวทางคลาสสิกสำหรับ DDD ไม่ได้ระบุว่าจะหลีกเลี่ยง Anemic vs Rich Models โดยเสียค่าใช้จ่ายทั้งหมด อย่างไรก็ตาม MDA ยังสามารถใช้แนวคิด DDD ทั้งหมดได้ (บริบทที่มีขอบเขต, แผนที่บริบท, ออบเจ็กต์ค่า ฯลฯ ) แต่ใช้โมเดล Anemic vs Rich ในทุกกรณี มีหลายกรณีที่การใช้บริการโดเมนเพื่อจัดเตรียมกรณีการใช้งานโดเมนที่ซับซ้อนในชุดการรวมโดเมนเป็นแนวทางที่ดีกว่าการเรียกใช้การรวมจากเลเยอร์แอปพลิเคชันเพียงอย่างเดียว ข้อแตกต่างเพียงอย่างเดียวจากแนวทาง DDD แบบคลาสสิกคือการตรวจสอบความถูกต้องและกฎเกณฑ์ทางธุรกิจทั้งหมดอยู่ที่ใด มีโครงสร้างใหม่ที่รู้ว่าเป็นตัวตรวจสอบโมเดล ผู้ตรวจสอบความถูกต้องจะตรวจสอบความสมบูรณ์ของรูปแบบการป้อนข้อมูลทั้งหมดก่อนที่จะมีกรณีการใช้งานหรือเวิร์กโฟลว์โดเมนเกิดขึ้น เอนทิตีรากรวมและเอนทิตีลูกเป็นโรคโลหิตจาง แต่แต่ละคนสามารถเรียกใช้ตัวตรวจสอบความถูกต้องของแบบจำลองของตนเองได้ตามความจำเป็น โดยเป็นโปรแกรมตรวจสอบรูท เครื่องมือตรวจสอบยังคงยึดติดกับ SRP ดูแลรักษาง่ายและสามารถทดสอบหน่วยได้

เหตุผลของการเปลี่ยนแปลงนี้คือตอนนี้เรากำลังมุ่งสู่ API มากขึ้นก่อนเทียบกับแนวทางแรกของ UX สำหรับ Microservices REST มีส่วนสำคัญอย่างยิ่งในเรื่องนี้ วิธีการ API แบบดั้งเดิม (เนื่องจาก SOAP) ได้รับการแก้ไขในขั้นต้นโดยใช้คำสั่ง API กับกริยา HTTP (POST, PUT, PATCH, GET และ DELETE) API ตามคำสั่งเข้ากันได้ดีกับแนวทางเชิงวัตถุ Rich Model และยังใช้ได้ดีมาก อย่างไรก็ตาม API ที่ใช้ CRUD แบบธรรมดาแม้ว่าจะสามารถใส่ใน Rich Model ได้ แต่ก็เหมาะกว่ามากกับโมเดลโรคโลหิตจางแบบง่ายตัวตรวจสอบความถูกต้องและบริการโดเมนเพื่อจัดเตรียมส่วนที่เหลือ

ฉันชอบ DDD ในทุกสิ่งที่มีให้ แต่มีบางครั้งที่คุณต้องยืดมันออกไปเล็กน้อยเพื่อให้เข้ากับสถาปัตยกรรมที่เปลี่ยนแปลงตลอดเวลาและดีขึ้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.