خانه / OOP / DDD / ValueObject vs Entity in DDD

ValueObject vs Entity in DDD

انواع متدهای بررسی برابری- Equality

قبل از مقایسه بین ValueObject  و Entity نیاز است که متدهایی بررسی برابری معرفی شوند

  • Reference equality

بدین معنی است که دو Object در صورتی برابر هستند که هر دو به آدرس مشابهی رفرنس داشته باشند.

object object1 = new object();

object object2 = object1;

bool areEqual = object.ReferenceEquals(object1, object2); // returns true

  • Identifier equality

بطور ضمنی اشاره داره که کلاس مورد نظر دارای id هست. و دو instance از یک کلاس در اینجا در صورتی برابر هستند که هر دو id برابری داشته باشند

  • structural equality

دو Instance در این شرایط در صورتی برابر هستند که تمام member ها آنها با هم برابر باشند

 

حالا بر می گردیم که بررسی تفاوت ValueObjectها و Entity ها؛ تفاوت اصلی این دو در این هست که context مربوط به Identifier equality اشاره داره به Entity و structural equality در مقابل به ValueObject ها اشاره دارد

در عمل این بدین معنیه که ValueObject ها دارای id نیستند و اگه دو object دارای attribute ها مشابهی باشند به سادگی هر دو interchangeable هستند.. پس اگه بطور همزمان دیتای هر دو ValueObjectی مشابه و برابر باشه نمی توان تفاوتی بین آنها قایل شد.

  • Lifespan

تفاوت دیگر بین این دو در مورد lifespan مربوط به instance ها آنها است. در مورد entity ها lifespance ها بصورت continuum هستش. در واقع Entity ها دارای History از تغییرات خود در تمام lifecycle خود هستند هر چند این تغییرات ذخیره نشود.

در مورد ValueObjectها این امر اما به عکس صادق است. و همین امر باعث خاصیت interchangeable بودن اونها میشه.

نکته مهم در اینجا این است که ValueObjectبدون وجود و حضور Entity مفهومی مستقلی نداره و نمیتونه وجود خارجی داشته باشه.به عنوان مثال میزان دارایی شخص را در نظر بگیرید. شخص Entity و دارای ValueObject هست. در انجا بدون در نظر گرفتن شخص در context ما معنی و مفهومی نداره. و همچنین Query هایی شبیه How much money? نمی تونه معنی داشته باشه.

و نکته ی مهم دیگر اینکه ما ValueObject ها بصورت جداگونه ذخیره نمی کنیم.

  • immutability

تفاوت مهم دیگر Immutability بودن هست. ValueObjectها باید Immutable باشند بدین معنی که اگر ما نیاز به تغییر یک ValueObject داشتیم براحتی بتونیم Instance دیگری از اون ValueObject ایجاد کنیم. روی دیگر قضیه برای Entity کاملا عکس هست و Entity ها کاملا mutableهستند.

باید در نظر داشت که در مورد Immutable بودن ValueObjectها دو دیدگاه متفاوت وجود داره و برخی چنین خصوصیتی رو برای ValueObjectها مهم در نظر نمی گیرند.

در اینجا باید گفت که اگر به lifespan که در مورد قبلی اشاره شد توجه کنیم اگر ما به zero lifespan در مورد ValueObjectها معتقد باشیم پس براحتی متوجه خواهیم شده که ValueObjectها باید immutable باشند و به محضی که نیاز به تغییر attributeی از یک ValueObject داشته باشیم بهتر است که instantiate بشه اون ValueObject مورد نظر. و البته این بحث گاهی به نتیجه مهم دیگه میرسه که در صورتی که نتونیم یک ValueOBject رو بصورت immutable درنظر بگیریم پس اون ValueObject بصورت یک Entity طراحی خواهد شد.

اما به چه صورت ValueObject ها رو درون Domain تشخصی داد؟

همیشه بوضح و براحتی نمی توان تشخیص داد که conceptی خاص در دامین شما ValueObject هست یا خیر؟ و این مسئله کاملا به دامنه ی راه حل شما بستگی دارد, و Conceptی می تواند در دامنه ای Entity و در دامنه ی دیگری ValueObject باشد.

به عنوان نمونه در مثالی که در بالا ذکر شد money چون کاملا Interchangable هست به عنوان ValueObject در دامین مورد نظر در نظر گرفته خواهد شد. اما در صورتی که در دامین مورد نظر ما نیاز به track کردن money داشته باشیم یا اینکه مثلا تعداد سکه و اسکناس های یک money مورد نظر رو نیاز داشته باشیم money بایستی بصورت Entity در نظر گرفته شود.

در نظر باید داشته باشیم که استفاده از id جهت تشخیص Entity یا ValueObject بودن در اینجا می تواند بسیار کمک کننده باشد؛ اگر بتوان بصورت Safe یک object رو با objectدیگری با attribute های مشابه عوض کرد این یک Sign بسیار خوبی جهت تشخیص ValueObject بودن هست.

البته این مورد در Scalar Valueها نمی تواند پاسخگو باشد. مثلا فرض کنید فیلدی بصورت integer باشد صرف اینکه 5 را بتوان به 5 جابجا نمود آیا می توان تصمیم گرفت که این object حتما ValueObject هست؟ بی شک خیر؟ صرفنظر از اینکه چگونه object مورد نظر instantiate می شود؛ تمام 5 ها درون application شما برابر هستند.

 

اما ValueObject رو به چه صورت درون دیتابیس ذخیره کنیم؟

فرض کنید که دو کلاس درون Domain Model خود داریم: Person entity و Address Value Object:

// Entity

public class Person

{

public int Id { get; set; }

public string Name { get; set; }

public Address Address { get; set; }

}

 

// Value Object

public class Address

{

public string City { get; set; }

public string ZipCode { get; set; }

}

 

 

در این حالت ساختار دیتابیس به چه صورت خواهد شد؟ اولین موردی که به ذهنمان خطور می کند؛ Separated tables هست. چنین طراحی بوضوح از دید database کاملا صحیح و بی عیب هست. اما از دیدی دیگر: ابتدا به ساکن Address دارای id هست!!! این بدین معنی است که ما مجبور به تعریف id برای جدول Address هستیم. و این موجب violate شدن تعریف اساسی ValueObject ها خواهد شد.

مورد بعدی در این طراحی این است که ما می توانیم براحتی ValueObject رو از Entity جدا کنیم و ValueObject بدون حضور Entity امکان وجود خواهد داشت. چون ما قادریم که Personی رو از جدول Person جدا کنیم بدون اینکه Address مربوط به اون حذف بشه. که این نیز موجب violate شدن lifespan خواهد شد که lifetime یک ValueObject کاملا بسته به Lifetime مربوط به Parent entity خواهد بود.

پس به نظر میرسه که بهترین solution ذخیره inline؛ ValueObject ها کنار entity می باشد.

Don’t introduce separate tables for value objects

 

Prefer value objects over entities

بهنگام کار با Entity و ValueObjectها ValueObject ها را نسبت به Entity ترجیح دهید. چون ValueObject ها immutable هستند و به نسبت Entity ها Lightweight هستند. و کار کردن به اونها به وضوح راحت تر است

ممکن است که concept در ابتدای کار بصورت entity در نظر گرفته شود؛ اما پس از refeinment نمودن Domain مشخص شود که ValueObjectاست. مثلا Address ابتدا بصورت Entity در نظر گرفته شود؛ و دارای id و یک جدول جداگانه باشد اما پس از مدتی مشخص شود که Address واقعا ValueObject هست. در همچین مواردی به هیچ وجه درنگ نکنید و شروع کنید به refactor نمودن.

خلاصه

  • Entity دارای id هستند و ValueObjectها خیر.
  • مفهوم identity equality اشاره به entity دارد و مفهوم structural equality به ValueObject ها اشاره دارد
  • Entityها دارای History هستند و ValueObjectها خیر-zero lifespan
  • یک ValueObjectهمیشه باید متعلق به یک یا چند entity باشد و بدون انها نمی تواند وجود داشته باشد.
  • ValueObjectها باید immutable باشد و entity ها همیشه mutable هستند
  • ValueObject ها نباید دارای جدولی حداگانه برای خود در دیتابیس باشند
  • همیشه ValueObject ها را نسبت به Entityها در دامین خود ترجیح دهید.

 

Trying to be Agile…

Masoud Bahrami

درباره ی masoud@admin

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

در تلگرام هم همراه شما هستم

اگر علاقمند به معماری نرم افزار و مبحث محبوب مایکروسرویس هستید؛ در کانال با ما همراه باشید. اطلاعات مفید زیادی در این کانال انتظار شما را می کشند. فقط کافیست دکمه ی پیوستن را بفشارید.

پیوستن بستن