اندازهی قلم متن
تخمین مدت زمان مطالعهی مطلب:
دو دقیقه
متد حسود یا Feature envy در دسته بندی «کدهایی بیش از اندازه، وابسته به هم» قرار میگیرد. چنین متدی بیش از آنکه از فیلدها و خصوصیات کلاس خود استفاده کند، از فیلدها و خصوصیات شیء دیگری از نوعی دیگر، استفاده میکند.
یکی از اشکالات کدهای بیش از اندازه وابسته به هم، دشواری در نگهداری و تغییر کد است. بهطوریکه در زمان تغییر بخشی از کد، نیاز است بخشهای مرتبط نیز مورد بررسی قرار گیرند. همچنین وابستگی بیش از اندازه کلاسها به یکدیگر قابلیت جداسازی و استفاده مجدد کلاسها را کاهش خواهد داد.
معمولا در نتیجهی جابجایی مسئولیتها، در بخشهای مختلف کد، شاهد چنین کد بد بویی هستیم. یکی از پر تکرارترین شرایط، زمانی است که تعدادی از متغیرهای متد، به کلاس داده خاص خود منتقل شوند.
به طور مثال:
در این کد یک کلاس برای ایجاد یک آیتم صورت حساب نوشته شده است که یک آیتم از قرارداد را به عنوان ورودی دریافت و سپس اقدام به ایجاد یک آیتم صورت حساب میکند.
public class OrderItem { public int Quantity { get; set; } public decimal UnitPrice { get; set; } public decimal Discount { get; set; } } public class InvoiceItemGenerator { private readonly OrderItem _orderItem; public InvoiceItemGenerator(OrderItem orderItem) { _orderItem = orderItem; } public dynamic Generate() { dynamic invoiceItem = new ExpandoObject(); invoiceItem.Amount = _orderItem.Quantity * _orderItem.UnitPrice - _orderItem.Discount; return invoiceItem; } }
اگر به متد Generate دقت کرده باشید متوجه خواهید شد که این متد از خصوصیات شی OrderItem استفاده بیش از اندازه میکند و در حال انجام محاسبهای است که ظاهرا بهتر بود جای دیگری باشد.
در این مثال خاص دو راه حل برای این موضوع وجود دارد:
اول: انتقال منطق محاسبه مبلغ نهایی آیتم، به کلاس OrderItem. مانند:
public class OrderItem { public int Quantity { get; set; } public decimal UnitPrice { get; set; } public decimal Discount { get; set; } public decimal GetFinalAmount() { return Quantity * UnitPrice - Discount; } } public class InvoiceItemGenerator { private readonly OrderItem _orderItem; public InvoiceItemGenerator(OrderItem orderItem) { _orderItem = orderItem; } public dynamic Generate() { dynamic invoiceItem = new ExpandoObject(); invoiceItem.Amount = _orderItem.GetFinalAmount(); return invoiceItem; } }
دوم: انقال کل منطق محاسبه قیمت به کلاسی مثلا با نام InvoiceItemAmountCalculator که در نوشتههای پیشین نمونهای از آن را مشاهده کردیم. در واقع در این روش استراتژی محاسبه قیمت را به صورت کلاسی مجزا پیاده سازی میکنیم.
به طور کلی روشهای رفع چنین بوی بدی به همین دو نوع برخورد ختم خواهد شد. ایجاد یک کلاس استراتژی از نظر اصل Single responsibility مفید است؛ ولی ممکن است کد را در دام «درخت ارث بری موازی» بیندازد.
جمع بندی
این کد بد بو نیز یکی از پرتکرارترین کدهای بد بوی قابل مشاهده در پروژههای نرم افزاری است. یکی از نتایج مستقیم این کد بد بو، وجود کدهای تکراری فراوان برای انجام روالهای تقریبا یکسان است که با رفع این بو به خوبی برطرف میشوند. همچنین رفع این بوی بد به افزایش قابلیت نگهداری کد نیز کمک بسیار زیادی میکند.