بررسی Bad code smell ها: میراث رد شده
نویسنده: فرید بکران
تاریخ: ۱۳۹۶/۰۴/۰۲ ۱۵:۱۰
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
میراث رد شده یا Refused bequest به دسته «بد استفاده کنندگان از شیء گرایی» تعلق دارد. این دسته از کدهای بد بو، معمولا استفاده ناقص یا نادرستی از مفاهیم و اصول شیء گرایی دارند.
زمانیکه یک کلاس تنها بخشی از اعضای (خصوصیت، متد و ...) کلاس پدر خود را استفاده میکند، با این الگو سر و کار داریم. در چنین شرایطی دیگر اعضای کلاس پدر یا استفاده نمیشوند و یا حتی در صورت پیاده سازی شدن توسط کلاس، بلااستفاده میمانند. به طور مثال متدهایی از کلاس پدر پیاده سازی میشوند و با پرتاب یک استثناء در بدنهشان از کار میافتند.
یکی از دلایل مهم ایجاد چنین کدهای بد بویی، ایجاد رابطه ارث بری تنها برای استفاده دوباره از کدهای یک کلاس است. در صورتیکه ممکن است کلاس پدر و فرزند هیچ ارتباط منطقی ای از نظر ارث بری با یکدیگر نداشته باشند.
به طور مثال فرض کنید در حال توسعه یک محصول هستید که در آن فروش کالا اتفاق میافتد. در ابتدای کار، تنها کاربران این محصول، شرکتها هستند. روالی نیز برای محاسبه تخفیف مربوط به شرکتها ایجاد شده است. در این روال یک تخفیف پایه وجود دارد که به همه مشتریان تعلق میگیرید و تخفیفهایی نیز وجود دارند که به هر یک از شرکتها تعلق میگیرند. میزان تخفیف نهایی برای یک شرکت از مجموع این دو مقدار بدست میآید. کلاس مربوط به محاسبه تخفیف به این صورت است:
public class DiscountCalculator
{
protected decimal CalculateGeneralDiscount()
{
// calculate general discount
return 0;
}
protected decimal AddSpecificDiscount(decimal baseDiscount)
{
// add specific discounts to base discount
return 0;
}
protected virtual decimal GetFinalDiscount()
{
var baseDiscount = CalculateGeneralDiscount();
var addedDiscount = AddSpecificDiscount(baseDiscount);
return addedDiscount;
}
} public class PersonDiscountCalculator : DiscountCalculator
{
private decimal AddSpecificDiscountForPerson(decimal baseDiscount)
{
// calculate base discount for person
return 0;
}
protected override decimal GetFinalDiscount()
{
var baseDiscount = CalculateGeneralDiscount();
var added = AddSpecificDiscountForPerson(baseDiscount);
return added;
}
}
public abstract class DiscountCalculator
{
protected decimal CalculateGeneralDiscount()
{
// calculate general discount
return 0;
}
protected abstract decimal AddSpecificDiscount(decimal baseDiscount);
protected virtual decimal GetFinalDiscount()
{
var baseDiscount = CalculateGeneralDiscount();
var addedDiscount = AddSpecificDiscount(baseDiscount);
return addedDiscount;
}
} public class CompanyDiscountCalculator: DiscountCalculator
{
protected override decimal AddSpecificDiscount(decimal baseDiscount)
{
// add some customer specific discounts to base discount
return 0;
}
}
public class PersonDiscountCalculator : DiscountCalculator
{
protected override decimal AddSpecificDiscount(decimal baseDiscount)
{
// calculate base discount for person
return 0;
}
}
در صورتیکه این کد بد بو اصلاح شود، معمولا با کدی قابل درکتر و با سازماندهی منطقی بهتری روبرو خواهیم بود. به طور کلی رعایت رابطه منطقی بین کلاسها، علاوه بر جلوگیری از بروز مشکل «میراث رد شده»، خوانایی کد را افزایش داده و اعمال تغییرات در آن را نیز آسانتر میکند.