قبل از پیاده سازی Domain Driven Design بیاید کمی در مورد Encapsulation و SoC بحث کنیم.
نقشی است که یکپارچگی داده ها محافظت میکند، یک کلاس زمانی به درستی encapsulate شده که داده های داخلی اون را نتوان با ارسال حالتهای نامعتبر و بی ثبات تغییر داد. دو تکنیک وجود دارد که به شما برای این کار کمک میکند، پنهان سازی اطلاعات و جمع آوری داده و انجام عملیات با یکدیگر.
پنهان سازی داده به شما این کمک را میکند که ویژگی ها، صفات و پراپرتی های داخلی کلاسها رو از دید Client دور کنید تا ریسک برهم زدن ویژگی های داخلی کلاس را کم کند.
جمع آوری داده و عملیات به شما این امکان را میدهد تا با استفاده از یک ورودی، بتوانید تمامی کارهای کلاس را انجام دهید.
یک فانون کلیدی دیگر که برای توسعه نرم افزار باید رعایت شود رعایت separation of concern می باشد، به بیان ساده تر این قانون رابطه بسیار نزدیکی به قانون Single Responsibility Principle دارد.
بدین معنی که اگر کلاس شما وظیقه این را بر عهده دارد که محصولات با ارزش را شناسایی کند اما در کنار آن اطلاعات مشتری را نیز نمایش دهد، این کلاس SoC را نقض میکند.
برای درک بهتر این موضوع به مثال زیر توجه کنید:
public static void Main(string[] args) { Product product = new Product() { Id=1, Name = "SmartPhone", Code = "Galaxy A" }; product.NoteWorthy(1); product.UserDetail(100); }
public class Product { public int Id { get; set; } public string Name { get; set; } public string Code { get; set; } public void NoteWorthy(int id) { //get noteworthy products } public void UserDetail(int userId) { //get user detail } }
public class Course { [Column("IsActive",TypeName="Char(1)")] public bool IsActive { get; set; } [Column("Students_enrolled",TypeName="int")] public int NumberOfStudents { get; set; } }
کلاس Product دو قانون ذکر شده فوق را نقض میکند، طبق قانون encapsulation هر کلاس باید مسئول امور داخلی خود باشد، اما با نگاه به تایع main متوجه میشیم که این مسئولیت از کلاس product صلب شده و یا بهتر باید گفت کلاس product طوری طراحی شده که در هر جایی از برنامه client میتواند به امور داهلی کلاس تصف داشته باشد و حالت State کلاس را تغییر دهد.
اما طبق قانون SoC ، هر کلاس باید تنها امور داخلی خود را انجام دهد و هر گونه تغییر رفتار در کلاس دیر قاون SoC را نقض میکند، اگر به کلاس product نگاهی بکنید به راحتی متوجه میشوید که متد UserDetail این قانون را نقض کرده است و به همین علت میتوان گفت که SoC بسیار نزدیک به SRP می باشد.
مثال دیگر که قانون SoC را نقض میکند را میتوانید در کلاس Course مشاهده کنید، در این کلاس دو موضوع وجود دارد.
1- Domain Modeling
2- ORM mapping
ابتدا به سراغ Encapsulation میرویم، همانطور که گفته شد هر کلاس باید مسئول امور داخلی خود باشد.
public static void Main(string[] args) { var product = Product.AddProduct(1, "SmartPhone", "Galaxy A"); product.NoteWorthy(1); }
public class Product { public int Id { get; private set; } public string Name { get; private set; } public string Code { get; private set; } public Product(int id, string name, string code) { //logic to check validity Id = id; Name = name; Code = code; } public void NoteWorthy(int id) { //get noteworthy products } public static Product AddProduct(int id, string name, string code) { return new Product(id, name, code); } }
همانطور که در بالا مشاهده میکنید ، متدی به نام AddProduct نوشته ایم که یک شی از Product را ایجاد میکند، با این تغییرات Client امکان تغییر property های کلاس Product را در کلاس Main نخواهد داشت.
قدم بعدی رعایت قانون SoC می باشد و همانطور که گفته شد به لطف EF Core میتوان Data modeling و ORM از از یکدیگر جدا کرد.
public class Course { public bool IsActive { get; set; } public int NumberOfStudents { get; set; } }
public class CourseConfiguration : IEntityTypeConfiguration<Course> { public void Configure(EntityTypeBuilder<Course> builder) { builder.Property(x => x.IsActive).HasColumnName("IsActive").HasColumnType("char(1)"); builder.Property(x => x.NumberOfStudents).HasColumnName("Students_enrolled").HasColumnType("int"); } }