اين قسمت از آشنايي با Refactoring به كاهش cyclomatic complexity اختصاص دارد و خلاصه آن اين است: «استفاده از if هاي تو در تو بيش از سه سطح، مذموم است» به اين علت كه پيچيدگي كدهاي نوشته شده را بالا برده و نگهداري آنها را مشكل ميكند. براي مثال به شبه كد زير دقت كنيد:
if if if if do something endif endif endif endif
كه حاصل آن شبيه به نوك يك پيكان (Arrow head) شده است. يك مثال بهتر:
namespace Refactoring.Day9.RemoveArrowhead.Before { public class Role { public string RoleName { set; get; } public string UserName { set; get; } } }
using System; using System.Collections.Generic; using System.Linq; namespace Refactoring.Day9.RemoveArrowhead.Before { public class RoleRepository { private IList<Role> _rolesList = new List<Role>(); public IEnumerable<Role> Roles { get { return _rolesList; } } public void AddRole(string username, string roleName) { if (!string.IsNullOrWhiteSpace(roleName)) { if (!string.IsNullOrWhiteSpace(username)) { if (!IsInRole(username, roleName)) { _rolesList.Add(new Role { UserName=username, RoleName=roleName }); } else { throw new InvalidOperationException("User is already in this role."); } } else { throw new ArgumentNullException("username"); } } else { throw new ArgumentNullException("roleName"); } } public bool IsInRole(string username, string roleName) { return _rolesList.Any(x => x.RoleName == roleName && x.UserName == username); } } }
متد AddRole فوق، نمونهي بارز پيچيدگي بيش از حد حاصل از اعمال if هاي تو در تو است و ... بسيار متداول. براي حذف اين نوك پيكان حاصل از if هاي تو در تو، از بالاترين سطح شروع كرده و شرطها را برعكس ميكنيم؛ با اين هدف كه هر چه سريعتر متد را ترك كرده و خاتمه دهيم:
using System; using System.Collections.Generic; using System.Linq; namespace Refactoring.Day9.RemoveArrowhead.After { public class RoleRepository { private IList<Role> _rolesList = new List<Role>(); public IEnumerable<Role> Roles { get { return _rolesList; } } public void AddRole(string username, string roleName) { if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentNullException("roleName"); if (string.IsNullOrWhiteSpace(username)) throw new ArgumentNullException("username"); if (IsInRole(username, roleName)) throw new InvalidOperationException("User is already in this role."); _rolesList.Add(new Role { UserName = username, RoleName = roleName }); } public bool IsInRole(string username, string roleName) { return _rolesList.Any(x => x.RoleName == roleName && x.UserName == username); } } }
اكنون پس از اعمال اين Refactoring ، متد AddRole بسيار خواناتر شده و هدف اصلي آن كه اضافه كردن يك شيء به ليست نقشها است، واضحتر به نظر ميرسد. به علاوه اينبار قسمتهاي مختلف متد AddRole، فقط يك كار را انجام ميدهند و وابستگيهاي آنها به يكديگر نيز كاهش يافته است.