بازسازی کد: ارتباط یک طرفه و دو طرفه بین کلاس ها
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: دو دقیقه

در طراحی شیء گرا، ارتباط کلاس‌ها امری عادی است. در صورتیکه فقط یکی از کلاس‌ها نیاز به شیء کلاس دیگری را داشته باشد، این ارتباط یک طرفه نامیده می‌شود و زمانیکه هر دو کلاس به اشیاء یکدیگر نیاز داشته باشند، دو طرفه نامیده می‌شود.
زمانیکه ارتباطی به صورت یک طرفه پیاده سازی شده باشد، ممکن است پس از مدتی نیاز به ارتباط برعکس بین کلاس‌ها بوجود بیاید. در این صورت ارتباط دوطرفه را با اضافه کردن یک خصوصیت ایجاد می‌کنیم. به طور مثال نرم افزاری را در نظر بگیرید که در آن دو موجودیت مشتری و سفارش وجود دارند و این موجودیت‌ها به صورت زیر طراحی شده‌اند:   

 
public class Customer 
{ 
    public string Name { get; set; } 
} 
public class Order 
{ 
    public Customer Customer { get; set; } 
}
در این طراحی، از شیء سفارش می‌توان در صورت نیاز به شیء مشتری مربوط به آن رسید. اما با در دست داشتن شیء مشتری، نمی‌توان به سفارش‌های آن دسترسی داشت؛ زیرا رفرنسی به سفارش در آن وجود ندارد. به عبارتی طراحی بالا نمایانگر شرایطی است که در آن زمان ثبت قرارداد می‌توانیم مشتری جدیدی را نیز ایجاد کنیم.
در صورت نیاز به ارتباط دوطرفه، برای ایجاد آن در این شرایط، خصوصیتی را که نشان دهنده سفارشات مشتری باشد، به کلاس مشتری اضافه می‌کنیم. در نتیجه، طراحی به صورت زیر تغییر می‌کند. این شرایط ممکن است زمانی بوجود بیاید که نیاز داریم با در دست داشتن شیء یک مشتری بتوانیم سفارشات مورد نظر وی را ایجاد کنیم. 

public class Customer 
{ 
    public string Name { get; set; } 
    public ICollection<Order> Orders { get; set; } 
} 
public class Order 
{ 
    public Customer Customer { get; set; } 
}

همان طور که با مثالهای آورده شده قابل مشاهده است، تصمیم به استفاده از ارتباط یک طرفه یا دوطرفه، تصمیمی صرفا فنی نیست و به شرایط قواعد کسب و کار نیز ارتباط می‌یابد. 

اگر از ORM در طراحی لایه دسترسی داده استفاده شود، معمولا ارتباط‌های دوطرفه در نگاه اول مشکل ساز به نظر نمی‌رسند، یا حتی لازم خواهند بود (برای استفاده از امکانات mapping بر اساس قرارداد). اما ارتباطات دو طرفه معمولا امکان دسترسی به اقلام اطلاعاتی را بدون در نظر گرفتن قواعد کسب و کاری لازم، بوجود می‌آورند. یکی از اشکالات اصلی طراحی با ارتباط دو طرفه ارتباط بیش از اندازه کلاس‌ها با یکدیگر است. در این صورت ممکن است تغییر در یک کلاس، به کلاس‌های دیگری نفوذ کند که این مورد خود یک الگوی کد بد بو است.

عموما با توجه به هزینه‌ای که ارتباط دو طرفه ایجاد می‌کند، بهتر است استفاده از آن، تا آخرین لحظه نیاز به تعویق بیفتد و اولویت طراحی با ارتباط یک طرفه باشد.  

  • #
    ‫۶ سال و ۷ ماه قبل، پنجشنبه ۳ اسفند ۱۳۹۶، ساعت ۲۰:۵۲
    در EF Code First اگر به این شکل تعریف کنیم
    public class Customer
    {
        public string Name { get; set; }
    }
    public class Order
    {
        public Customer Customer { get; set; }
    }
    تکلیف  Navigation Property  چی میشه ؟
    بالاخره مجبوریم برای کوئری و همینطور Relation  از حالت زیر که شما انتقاد داشتین استفاده کنیم
    public class Customer
    {
        public string Name { get; set; }
        public ICollection<Order> Orders { get; set; }
    }
    public class Order
    {
        public Customer Customer { get; set; }
    }

    راهکار درست دیگری وجود دارد ؟
    با تشکر
    • #
      ‫۶ سال و ۶ ماه قبل، جمعه ۴ اسفند ۱۳۹۶، ساعت ۰۶:۰۸
      بنده به هیچ کدام از این روش‌ها انتقادی نداشتم. تصمیم طراحی باید بر اساس شرایط پروژه اتخاد بشه. 
      در مورد استفاده از navigation property 
      در entity framework استفاده از Navigation property برعکس (در مثال شما کالکشن Orders در کلاس Customer) برای ایجاد یک رابطه یک به چند الزامی نیست. (برای ایجاد relation نیازی به حضوری این collection نیست و حضور خصوصیت Customer در کلاس Order کافی است) و در صورتی که شما از نظر کسب و کاری نیازی به چنین خصوصیتی نداشته باشید می‌توانید از ایجاد آن صرف نظر کنید. 
      public class Order
      {
          public int Id { get; set; }
          public Customer Customer { get; set; }
      }
      public class Customer
      {
          public int Id { get; set; }
      }
      ......
      
      modelBuilder.Entity<Order>().HasRequired(ff => ff.Customer);


      حضور خصوصیت Orders در کلاس Customer در مثال شما از نظر کسب و کاری به این معنی است که شما برای رسیدن به لیست سفارشات نیاز دارید که به شی مشتری دسترسی پیدا کنید. 
      نکته اصلی این بازسازی کد اجتناب از استفاده بی مورد ارتباط دوطرفه است.