public RedirectToRouteResult Ship(int orderId) { var status = _orderShippingService.Ship(orderId); if (status.Successful) { return RedirectToAction("Shipped", "Order", new {orderId}); } return RedirectToAction("NotShipped", "Order", new {id = orderId, desc = status}); }
روشهای اصلاح این کد بد بو
- لیست محصولات فروخته شده
- درصد کمیسیون خام
- تاریخ فروش
- شعبه فروش
- نوع پرداخت
public class Salesman { public void Method1() { return; } public void Method2() { return; } public void Method3() { return; } public decimal CalculateCommission(dynamic products, dynamic commissionRate, dynamic saleDate, dynamic branch, dynamic paymentType) { return decimal.MaxValue; } }
public class SalesmanV2 { public IEnumerable<dynamic> Products { get; set; } public dynamic CommisionRate { get; set; } public dynamic SaleDate { get; set; } public dynamic Branch { get; set; } public dynamic PaymentType { get; set; } public void Method1() { return; } public void Method2() { return; } public void Method3() { return; } public decimal CalculateCommission() { return decimal.MaxValue; } }
public class SalesmanV3 { public void Method1() { return; } public void Method2() { return; } public void Method3() { return; } }
public class CommissionCalculator { private IEnumerable<dynamic> _products; private dynamic _commisionRate; private dynamic _saleDate; private dynamic _branch; private dynamic _paymentType; public CommissionCalculator(IEnumerable<dynamic> products, dynamic commisionRate, dynamic saleDate, dynamic branch, dynamic paymentType) { _products = products; _commisionRate = commisionRate; _saleDate = saleDate; _branch = branch; _paymentType = paymentType; } }
جمع بندی
میراث رد شده یا 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; } }
جمع بندی
در صورتیکه این کد بد بو اصلاح شود، معمولا با کدی قابل درکتر و با سازماندهی منطقی بهتری روبرو خواهیم بود. به طور کلی رعایت رابطه منطقی بین کلاسها، علاوه بر جلوگیری از بروز مشکل «میراث رد شده»، خوانایی کد را افزایش داده و اعمال تغییرات در آن را نیز آسانتر میکند.
public class EfTagService : ITagService { IUnitOfWork _uow; readonly IDbSet<Tag> _tags; public EfTagService(IUnitOfWork uow) { _uow = uow; _tags = _uow.Set<Tag>(); } public bool CreateTag(Tag tag) { // ... } public List<Tag> GetTagsByName(string[] tagNames) { // return ... } }
public class EfPostService : IPostService { IUnitOfWork _uow; readonly IDbSet<Post> _posts; //این قسمت private EfTagService _tagService; public EfPostService(IUnitOfWork uow) { _uow = uow; _posts = uow.Set<Post>(); //این قسمت _tagService = new EfTagService(_uow); } public void AddTagsToPost(Post post, string[] tagsList) { if (post.Tags != null && post.Tags.Any()) post.Tags.Clear(); //این قسمت var listOfActualTags = _tagService.GetTagsByName(tagsList); var listOfActualTagNames = listOfActualTags.Select(x => x.Name.ToLower()).ToList(); foreach (var tag in tagsList) { if (!listOfActualTagNames.Contains(tag.ToLowerInvariant().Trim())) { Tag newTag = new Tag() { Name = tag }; //این قسمت _tagService.CreateTag(newTag); post.Tags.Add(newTag); } } // ... } }
<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files"> <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" staticCompressionLevel="9" dynamicCompressionLevel="4" /> <scheme name="deflate" dll="%Windir%\system32\inetsrv\gzip.dll" staticCompressionLevel="9" dynamicCompressionLevel="4" /> <dynamicTypes> <add mimeType="text/*" enabled="true" /> <add mimeType="message/*" enabled="true" /> <add mimeType="application/x-javascript" enabled="true" /> <add mimeType="application/atom+xml; charset=utf-8" enabled="true" /> <add mimeType="*/*" enabled="false" /> </dynamicTypes> <staticTypes> <add mimeType="text/*" enabled="true" /> <add mimeType="message/*" enabled="true" /> <add mimeType="application/javascript" enabled="true" /> <add mimeType="*/*" enabled="false" /> </staticTypes> </httpCompression>
بررسی نحوهی راه اندازی پروژهی Decision